| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | __filename__ = "person.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							| 
									
										
										
										
											2024-12-22 23:37:30 +00:00
										 |  |  | __version__ = "1.6.0" | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							| 
									
										
										
										
											2021-09-10 16:14:50 +00:00
										 |  |  | __email__ = "bob@libreserver.org" | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | __status__ = "Production" | 
					
						
							| 
									
										
										
										
											2021-06-15 15:08:12 +00:00
										 |  |  | __module_group__ = "ActivityPub" | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-11 18:03:58 +00:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2019-07-12 14:31:56 +00:00
										 |  |  | import subprocess | 
					
						
							| 
									
										
										
										
											2019-08-13 11:59:38 +00:00
										 |  |  | import shutil | 
					
						
							| 
									
										
										
										
											2020-06-21 16:02:52 +00:00
										 |  |  | import pyqrcode | 
					
						
							| 
									
										
										
										
											2020-01-19 23:24:23 +00:00
										 |  |  | from random import randint | 
					
						
							| 
									
										
										
										
											2019-07-12 14:31:56 +00:00
										 |  |  | from pathlib import Path | 
					
						
							| 
									
										
										
										
											2021-02-04 17:26:00 +00:00
										 |  |  | from cryptography.hazmat.backends import default_backend | 
					
						
							|  |  |  | from cryptography.hazmat.primitives.asymmetric import rsa | 
					
						
							|  |  |  | from cryptography.hazmat.primitives import serialization | 
					
						
							| 
									
										
										
										
											2019-07-12 13:51:04 +00:00
										 |  |  | from shutil import copyfile | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | from webfinger import create_webfinger_endpoint | 
					
						
							|  |  |  | from webfinger import store_webfinger_endpoint | 
					
						
							|  |  |  | from posts import get_user_url | 
					
						
							|  |  |  | from posts import create_dm_timeline | 
					
						
							|  |  |  | from posts import create_replies_timeline | 
					
						
							|  |  |  | from posts import create_media_timeline | 
					
						
							|  |  |  | from posts import create_news_timeline | 
					
						
							|  |  |  | from posts import create_blogs_timeline | 
					
						
							|  |  |  | from posts import create_features_timeline | 
					
						
							|  |  |  | from posts import create_bookmarks_timeline | 
					
						
							|  |  |  | from posts import create_inbox | 
					
						
							|  |  |  | from posts import create_outbox | 
					
						
							|  |  |  | from posts import create_moderation | 
					
						
							| 
									
										
										
										
											2021-12-28 21:36:27 +00:00
										 |  |  | from auth import store_basic_credentials | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | from auth import remove_password | 
					
						
							| 
									
										
										
										
											2021-12-28 22:22:09 +00:00
										 |  |  | from roles import set_role | 
					
						
							| 
									
										
										
										
											2022-09-02 18:06:13 +00:00
										 |  |  | from roles import actor_roles_from_list | 
					
						
							| 
									
										
										
										
											2021-12-28 22:22:09 +00:00
										 |  |  | from roles import get_actor_roles_list | 
					
						
							| 
									
										
										
										
											2021-12-28 21:36:27 +00:00
										 |  |  | from media import process_meta_data | 
					
						
							| 
									
										
										
										
											2024-09-13 13:58:14 +00:00
										 |  |  | from flags import is_image_file | 
					
						
							| 
									
										
										
										
											2025-02-04 10:32:19 +00:00
										 |  |  | from utils import get_person_icon | 
					
						
							| 
									
										
										
										
											2024-09-13 12:09:20 +00:00
										 |  |  | from utils import account_is_indexable | 
					
						
							| 
									
										
										
										
											2024-02-05 20:05:00 +00:00
										 |  |  | from utils import get_image_mime_type | 
					
						
							| 
									
										
										
										
											2024-01-29 21:45:04 +00:00
										 |  |  | from utils import get_instance_url | 
					
						
							| 
									
										
										
										
											2023-12-09 14:18:24 +00:00
										 |  |  | from utils import get_url_from_post | 
					
						
							| 
									
										
										
										
											2023-11-20 22:27:58 +00:00
										 |  |  | from utils import date_utcnow | 
					
						
							| 
									
										
										
										
											2023-09-01 09:22:38 +00:00
										 |  |  | from utils import get_memorials | 
					
						
							|  |  |  | from utils import is_account_dir | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  | from utils import valid_hash_tag | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  | from utils import acct_handle_dir | 
					
						
							| 
									
										
										
										
											2022-07-22 10:54:57 +00:00
										 |  |  | from utils import safe_system_string | 
					
						
							| 
									
										
										
										
											2022-05-11 17:39:23 +00:00
										 |  |  | from utils import get_attachment_property_value | 
					
						
							| 
									
										
										
										
											2022-03-14 15:51:12 +00:00
										 |  |  | from utils import get_nickname_from_actor | 
					
						
							| 
									
										
										
										
											2021-12-27 15:43:22 +00:00
										 |  |  | from utils import remove_html | 
					
						
							| 
									
										
										
										
											2021-12-27 17:53:41 +00:00
										 |  |  | from utils import contains_invalid_chars | 
					
						
							| 
									
										
										
										
											2022-12-26 10:49:41 +00:00
										 |  |  | from utils import contains_invalid_actor_url_chars | 
					
						
							| 
									
										
										
										
											2021-12-26 17:21:37 +00:00
										 |  |  | from utils import replace_users_with_at | 
					
						
							| 
									
										
										
										
											2022-06-21 11:58:50 +00:00
										 |  |  | from utils import remove_eol | 
					
						
							| 
									
										
										
										
											2021-12-26 18:17:37 +00:00
										 |  |  | from utils import remove_domain_port | 
					
						
							| 
									
										
										
										
											2021-12-27 17:42:35 +00:00
										 |  |  | from utils import get_status_number | 
					
						
							| 
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 |  |  | from utils import get_full_domain | 
					
						
							| 
									
										
										
										
											2021-12-28 14:41:10 +00:00
										 |  |  | from utils import valid_nickname | 
					
						
							| 
									
										
										
										
											2021-12-26 15:13:34 +00:00
										 |  |  | from utils import load_json | 
					
						
							| 
									
										
										
										
											2021-12-26 14:47:21 +00:00
										 |  |  | from utils import save_json | 
					
						
							| 
									
										
										
										
											2021-12-27 20:38:02 +00:00
										 |  |  | from utils import set_config_param | 
					
						
							| 
									
										
										
										
											2021-12-26 14:08:58 +00:00
										 |  |  | from utils import get_config_param | 
					
						
							| 
									
										
										
										
											2021-12-26 12:10:21 +00:00
										 |  |  | from utils import refresh_newswire | 
					
						
							| 
									
										
										
										
											2021-12-27 17:20:01 +00:00
										 |  |  | from utils import get_protocol_prefixes | 
					
						
							| 
									
										
										
										
											2021-12-26 12:19:00 +00:00
										 |  |  | from utils import has_users_path | 
					
						
							| 
									
										
										
										
											2021-12-26 14:26:16 +00:00
										 |  |  | from utils import get_image_extensions | 
					
						
							| 
									
										
										
										
											2021-12-26 12:02:29 +00:00
										 |  |  | from utils import acct_dir | 
					
						
							| 
									
										
										
										
											2021-12-26 12:24:40 +00:00
										 |  |  | from utils import get_user_paths | 
					
						
							| 
									
										
										
										
											2021-12-26 17:53:07 +00:00
										 |  |  | from utils import get_group_paths | 
					
						
							| 
									
										
										
										
											2021-12-26 10:19:59 +00:00
										 |  |  | from utils import local_actor_url | 
					
						
							| 
									
										
										
										
											2021-12-27 21:44:48 +00:00
										 |  |  | from utils import dangerous_svg | 
					
						
							| 
									
										
										
										
											2022-06-10 11:43:33 +00:00
										 |  |  | from utils import text_in_file | 
					
						
							| 
									
										
										
										
											2023-08-14 18:46:27 +00:00
										 |  |  | from utils import contains_statuses | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  | from utils import get_actor_from_post | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  | from utils import data_dir | 
					
						
							| 
									
										
										
										
											2023-08-13 09:58:02 +00:00
										 |  |  | from session import get_json_valid | 
					
						
							| 
									
										
										
										
											2021-12-28 16:56:57 +00:00
										 |  |  | from session import create_session | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | from session import get_json | 
					
						
							|  |  |  | from webfinger import webfinger_handle | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  | from pprint import pprint | 
					
						
							| 
									
										
										
										
											2024-01-29 21:45:04 +00:00
										 |  |  | from cache import get_actor_public_key_from_id | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | from cache import get_person_from_cache | 
					
						
							|  |  |  | from cache import store_person_in_cache | 
					
						
							| 
									
										
										
										
											2023-09-01 09:22:38 +00:00
										 |  |  | from cache import remove_person_from_cache | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | from filters import is_filtered_bio | 
					
						
							| 
									
										
										
										
											2021-12-28 20:32:11 +00:00
										 |  |  | from follow import is_following_actor | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def generate_rsa_key() -> (str, str): | 
					
						
							| 
									
										
										
										
											2022-06-12 10:58:00 +00:00
										 |  |  |     """Creates an RSA key for signing
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-02-04 17:26:00 +00:00
										 |  |  |     key = rsa.generate_private_key( | 
					
						
							|  |  |  |         public_exponent=65537, | 
					
						
							|  |  |  |         key_size=2048, | 
					
						
							|  |  |  |         backend=default_backend() | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     private_key_pem = key.private_bytes( | 
					
						
							| 
									
										
										
										
											2021-02-04 17:26:00 +00:00
										 |  |  |         encoding=serialization.Encoding.PEM, | 
					
						
							|  |  |  |         format=serialization.PrivateFormat.TraditionalOpenSSL, | 
					
						
							|  |  |  |         encryption_algorithm=serialization.NoEncryption() | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     pubkey = key.public_key() | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     public_key_pem = pubkey.public_bytes( | 
					
						
							| 
									
										
										
										
											2021-02-04 17:26:00 +00:00
										 |  |  |         encoding=serialization.Encoding.PEM, | 
					
						
							|  |  |  |         format=serialization.PublicFormat.SubjectPublicKeyInfo, | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     private_key_pem = private_key_pem.decode("utf-8") | 
					
						
							|  |  |  |     public_key_pem = public_key_pem.decode("utf-8") | 
					
						
							|  |  |  |     return private_key_pem, public_key_pem | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def set_profile_image(base_dir: str, http_prefix: str, | 
					
						
							|  |  |  |                       nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                       port: int, image_filename: str, image_type: str, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                       resolution: str, city: str, | 
					
						
							|  |  |  |                       content_license_url: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-07-12 13:51:04 +00:00
										 |  |  |     """Saves the given image file as an avatar or background
 | 
					
						
							|  |  |  |     image for the given person | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-06-21 11:58:50 +00:00
										 |  |  |     image_filename = remove_eol(image_filename) | 
					
						
							| 
									
										
										
										
											2021-12-27 15:58:46 +00:00
										 |  |  |     if not is_image_file(image_filename): | 
					
						
							| 
									
										
										
										
											2021-01-11 22:27:57 +00:00
										 |  |  |         print('Profile image must be png, jpg, gif or svg format') | 
					
						
							| 
									
										
										
										
											2019-07-12 14:31:56 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-07-12 13:51:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 14:42:21 +00:00
										 |  |  |     if image_filename.startswith('~/'): | 
					
						
							|  |  |  |         image_filename = image_filename.replace('~/', str(Path.home()) + '/') | 
					
						
							| 
									
										
										
										
											2019-07-12 14:31:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 18:17:37 +00:00
										 |  |  |     domain = remove_domain_port(domain) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     full_domain = get_full_domain(domain, port) | 
					
						
							| 
									
										
										
										
											2019-07-12 13:51:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 09:16:03 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |     person_filename = acct_handle_dir(base_dir, handle) + '.json' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not os.path.isfile(person_filename): | 
					
						
							|  |  |  |         print('person definition not found: ' + person_filename) | 
					
						
							| 
									
										
										
										
											2019-07-12 14:31:56 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |     handle_dir = acct_handle_dir(base_dir, handle) | 
					
						
							|  |  |  |     if not os.path.isdir(handle_dir): | 
					
						
							|  |  |  |         print('Account not found: ' + handle_dir) | 
					
						
							| 
									
										
										
										
											2019-07-12 14:31:56 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-07-12 13:51:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     icon_filename_base = 'icon' | 
					
						
							|  |  |  |     if image_type in ('avatar', 'icon'): | 
					
						
							|  |  |  |         icon_filename_base = 'icon' | 
					
						
							| 
									
										
										
										
											2019-07-12 13:51:04 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         icon_filename_base = 'image' | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     media_type = 'image/png' | 
					
						
							|  |  |  |     icon_filename = icon_filename_base + '.png' | 
					
						
							| 
									
										
										
										
											2024-02-05 19:07:55 +00:00
										 |  |  |     extensions = get_image_extensions() | 
					
						
							|  |  |  |     for ext in extensions: | 
					
						
							|  |  |  |         if image_filename.endswith('.' + ext): | 
					
						
							| 
									
										
										
										
											2024-02-05 20:05:00 +00:00
										 |  |  |             media_type = get_image_mime_type(image_filename) | 
					
						
							| 
									
										
										
										
											2024-02-05 19:07:55 +00:00
										 |  |  |             icon_filename = icon_filename_base + '.' + ext | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |     profile_filename = acct_handle_dir(base_dir, handle) + '/' + icon_filename | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     person_json = load_json(person_filename) | 
					
						
							|  |  |  |     if person_json: | 
					
						
							|  |  |  |         person_json[icon_filename_base]['mediaType'] = media_type | 
					
						
							|  |  |  |         person_json[icon_filename_base]['url'] = \ | 
					
						
							|  |  |  |             local_actor_url(http_prefix, nickname, full_domain) + \ | 
					
						
							|  |  |  |             '/' + icon_filename | 
					
						
							|  |  |  |         save_json(person_json, person_filename) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         cmd = \ | 
					
						
							| 
									
										
										
										
											2022-07-22 10:54:57 +00:00
										 |  |  |             '/usr/bin/convert ' + safe_system_string(image_filename) + \ | 
					
						
							|  |  |  |             ' -size ' + resolution + ' -quality 50 ' + \ | 
					
						
							|  |  |  |             safe_system_string(profile_filename) | 
					
						
							| 
									
										
										
										
											2019-07-12 14:31:56 +00:00
										 |  |  |         subprocess.call(cmd, shell=True) | 
					
						
							| 
									
										
										
										
											2021-12-28 21:36:27 +00:00
										 |  |  |         process_meta_data(base_dir, nickname, domain, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                           profile_filename, profile_filename, city, | 
					
						
							| 
									
										
										
										
											2021-12-28 21:36:27 +00:00
										 |  |  |                           content_license_url) | 
					
						
							| 
									
										
										
										
											2019-07-12 14:31:56 +00:00
										 |  |  |         return True | 
					
						
							|  |  |  |     return False | 
					
						
							| 
									
										
										
										
											2019-07-12 13:51:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def _account_exists(base_dir: str, nickname: str, domain: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-09 16:33:45 +00:00
										 |  |  |     """Returns true if the given account exists
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-26 18:17:37 +00:00
										 |  |  |     domain = remove_domain_port(domain) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |     return os.path.isdir(account_dir) or \ | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |         os.path.isdir(base_dir + '/deactivated/' + nickname + '@' + domain) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-09 16:33:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  | def randomize_actor_images(person_json: {}) -> None: | 
					
						
							| 
									
										
										
										
											2020-01-19 23:24:23 +00:00
										 |  |  |     """Randomizes the filenames for avatar image and background
 | 
					
						
							|  |  |  |     This causes other instances to update their cached avatar image | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     person_id = person_json['id'] | 
					
						
							| 
									
										
										
										
											2023-12-09 14:18:24 +00:00
										 |  |  |     url_str = get_url_from_post(person_json['icon']['url']) | 
					
						
							|  |  |  |     last_part_of_filename = url_str.split('/')[-1] | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     existing_extension = last_part_of_filename.split('.')[1] | 
					
						
							| 
									
										
										
										
											2020-07-08 15:09:27 +00:00
										 |  |  |     # NOTE: these files don't need to have cryptographically | 
					
						
							|  |  |  |     # secure names | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     rand_str = str(randint(10000000000000, 99999999999999))  # nosec | 
					
						
							|  |  |  |     base_url = person_id.split('/users/')[0] | 
					
						
							|  |  |  |     nickname = person_json['preferredUsername'] | 
					
						
							|  |  |  |     person_json['icon']['url'] = \ | 
					
						
							|  |  |  |         base_url + '/system/accounts/avatars/' + nickname + \ | 
					
						
							|  |  |  |         '/avatar' + rand_str + '.' + existing_extension | 
					
						
							| 
									
										
										
										
											2023-12-09 14:18:24 +00:00
										 |  |  |     url_str = get_url_from_post(person_json['image']['url']) | 
					
						
							|  |  |  |     last_part_of_filename = url_str.split('/')[-1] | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     existing_extension = last_part_of_filename.split('.')[1] | 
					
						
							|  |  |  |     rand_str = str(randint(10000000000000, 99999999999999))  # nosec | 
					
						
							|  |  |  |     person_json['image']['url'] = \ | 
					
						
							|  |  |  |         base_url + '/system/accounts/headers/' + nickname + \ | 
					
						
							|  |  |  |         '/image' + rand_str + '.' + existing_extension | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def get_actor_update_json(actor_json: {}) -> {}: | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |     """Returns the json for an Person Update
 | 
					
						
							| 
									
										
										
										
											2021-09-30 13:28:43 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     pub_number, _ = get_status_number() | 
					
						
							|  |  |  |     manually_approves_followers = actor_json['manuallyApprovesFollowers'] | 
					
						
							| 
									
										
										
										
											2023-08-27 09:30:20 +00:00
										 |  |  |     memorial = False | 
					
						
							|  |  |  |     if actor_json.get('memorial'): | 
					
						
							|  |  |  |         memorial = True | 
					
						
							| 
									
										
										
										
											2024-09-13 12:09:20 +00:00
										 |  |  |     indexable = account_is_indexable(actor_json) | 
					
						
							| 
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 |  |  |     searchable_by: list[str] = [] | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |     if actor_json.get('searchableBy'): | 
					
						
							|  |  |  |         if isinstance(actor_json['searchableBy'], list): | 
					
						
							|  |  |  |             searchable_by = actor_json['searchableBy'] | 
					
						
							| 
									
										
										
										
											2023-12-09 14:18:24 +00:00
										 |  |  |     actor_url = get_url_from_post(actor_json['url']) | 
					
						
							|  |  |  |     icon_url = get_url_from_post(actor_json['icon']['url']) | 
					
						
							|  |  |  |     image_url = get_url_from_post(actor_json['image']['url']) | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |     return { | 
					
						
							|  |  |  |         '@context': [ | 
					
						
							|  |  |  |             "https://www.w3.org/ns/activitystreams", | 
					
						
							|  |  |  |             "https://w3id.org/security/v1", | 
					
						
							| 
									
										
										
										
											2021-09-30 13:28:43 +00:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |                 "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", | 
					
						
							| 
									
										
										
										
											2023-08-27 09:39:46 +00:00
										 |  |  |                 "indexable": "toot:indexable", | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |                 "searchableBy": { | 
					
						
							|  |  |  |                     "@id": "fedibird:searchableBy", | 
					
						
							|  |  |  |                     "@type": "@id" | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2023-08-27 09:39:46 +00:00
										 |  |  |                 "memorial": "toot:memorial", | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |                 "toot": "http://joinmastodon.org/ns#", | 
					
						
							|  |  |  |                 "featured": | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "@id": "toot:featured", | 
					
						
							|  |  |  |                     "@type": "@id" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "featuredTags": | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "@id": "toot:featuredTags", | 
					
						
							|  |  |  |                     "@type": "@id" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "alsoKnownAs": | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "@id": "as:alsoKnownAs", | 
					
						
							|  |  |  |                     "@type": "@id" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "movedTo": | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "@id": "as:movedTo", | 
					
						
							|  |  |  |                     "@type": "@id" | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2022-05-11 14:34:05 +00:00
										 |  |  |                 "schema": "http://schema.org/", | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |                 "PropertyValue": "schema:PropertyValue", | 
					
						
							|  |  |  |                 "value": "schema:value", | 
					
						
							|  |  |  |                 "IdentityProof": "toot:IdentityProof", | 
					
						
							|  |  |  |                 "discoverable": "toot:discoverable", | 
					
						
							|  |  |  |                 "Device": "toot:Device", | 
					
						
							|  |  |  |                 "Ed25519Signature": "toot:Ed25519Signature", | 
					
						
							|  |  |  |                 "Ed25519Key": "toot:Ed25519Key", | 
					
						
							|  |  |  |                 "Curve25519Key": "toot:Curve25519Key", | 
					
						
							|  |  |  |                 "EncryptedMessage": "toot:EncryptedMessage", | 
					
						
							|  |  |  |                 "publicKeyBase64": "toot:publicKeyBase64", | 
					
						
							|  |  |  |                 "deviceId": "toot:deviceId", | 
					
						
							|  |  |  |                 "claim": | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "@type": "@id", | 
					
						
							|  |  |  |                     "@id": "toot:claim" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "fingerprintKey": | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "@type": "@id", | 
					
						
							|  |  |  |                     "@id": "toot:fingerprintKey" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "identityKey": | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "@type": "@id", | 
					
						
							|  |  |  |                     "@id": "toot:identityKey" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "devices": | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "@type": "@id", | 
					
						
							|  |  |  |                     "@id": "toot:devices" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "messageFranking": "toot:messageFranking", | 
					
						
							|  |  |  |                 "messageType": "toot:messageType", | 
					
						
							|  |  |  |                 "cipherText": "toot:cipherText", | 
					
						
							|  |  |  |                 "suspended": "toot:suspended", | 
					
						
							|  |  |  |                 "focalPoint": | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "@container": "@list", | 
					
						
							|  |  |  |                     "@id": "toot:focalPoint" | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-09-30 13:28:43 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         'id': actor_json['id'] + '#updates/' + pub_number, | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |         'type': 'Update', | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |         'actor': actor_json['id'], | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |         'to': ['https://www.w3.org/ns/activitystreams#Public'], | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |         'cc': [actor_json['id'] + '/followers'], | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |         'object': { | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |             'id': actor_json['id'], | 
					
						
							|  |  |  |             'type': actor_json['type'], | 
					
						
							| 
									
										
										
										
											2021-09-30 15:14:05 +00:00
										 |  |  |             'icon': { | 
					
						
							|  |  |  |                 'type': 'Image', | 
					
						
							| 
									
										
										
										
											2023-12-09 14:18:24 +00:00
										 |  |  |                 'url': icon_url | 
					
						
							| 
									
										
										
										
											2021-09-30 15:14:05 +00:00
										 |  |  |             }, | 
					
						
							|  |  |  |             'image': { | 
					
						
							|  |  |  |                 'type': 'Image', | 
					
						
							| 
									
										
										
										
											2023-12-09 14:18:24 +00:00
										 |  |  |                 'url': image_url | 
					
						
							| 
									
										
										
										
											2021-09-30 15:14:05 +00:00
										 |  |  |             }, | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |             'attachment': actor_json['attachment'], | 
					
						
							|  |  |  |             'following': actor_json['id'] + '/following', | 
					
						
							|  |  |  |             'followers': actor_json['id'] + '/followers', | 
					
						
							|  |  |  |             'inbox': actor_json['id'] + '/inbox', | 
					
						
							|  |  |  |             'outbox': actor_json['id'] + '/outbox', | 
					
						
							|  |  |  |             'featured': actor_json['id'] + '/collections/featured', | 
					
						
							|  |  |  |             'featuredTags': actor_json['id'] + '/collections/tags', | 
					
						
							|  |  |  |             'preferredUsername': actor_json['preferredUsername'], | 
					
						
							|  |  |  |             'name': actor_json['name'], | 
					
						
							|  |  |  |             'summary': actor_json['summary'], | 
					
						
							| 
									
										
										
										
											2023-12-09 14:18:24 +00:00
										 |  |  |             'url': actor_url, | 
					
						
							| 
									
										
										
										
											2024-01-07 13:45:53 +00:00
										 |  |  |             'vcard:Address': '', | 
					
						
							|  |  |  |             'vcard:bday': '', | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             'manuallyApprovesFollowers': manually_approves_followers, | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |             'discoverable': actor_json['discoverable'], | 
					
						
							| 
									
										
										
										
											2023-08-27 09:30:20 +00:00
										 |  |  |             'memorial': memorial, | 
					
						
							|  |  |  |             'indexable': indexable, | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |             'published': actor_json['published'], | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |             'searchableBy': searchable_by, | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |             'devices': actor_json['devices'], | 
					
						
							| 
									
										
										
										
											2023-08-27 09:30:20 +00:00
										 |  |  |             "publicKey": actor_json['publicKey'] | 
					
						
							| 
									
										
										
										
											2021-09-30 13:28:43 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-09-30 14:19:01 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-09-30 13:28:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-23 20:12:58 +00:00
										 |  |  | def get_actor_move_json(actor_json: {}) -> {}: | 
					
						
							|  |  |  |     """Returns the json for a Move activity after movedTo has been set
 | 
					
						
							|  |  |  |     within the actor | 
					
						
							|  |  |  |     https://codeberg.org/fediverse/fep/src/branch/main/fep/7628/fep-7628.md | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not actor_json.get('movedTo'): | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     if '://' not in actor_json['movedTo'] or \ | 
					
						
							|  |  |  |        '.' not in actor_json['movedTo']: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     if actor_json['movedTo'] == actor_json['id']: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     pub_number, _ = get_status_number() | 
					
						
							|  |  |  |     return { | 
					
						
							| 
									
										
										
										
											2024-09-14 16:40:11 +00:00
										 |  |  |         "@context": [ | 
					
						
							|  |  |  |             'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |             'https://w3id.org/security/v1' | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2023-09-23 20:12:58 +00:00
										 |  |  |         "id": actor_json['id'] + '#moved/' + pub_number, | 
					
						
							|  |  |  |         "type": "Move", | 
					
						
							|  |  |  |         "actor": actor_json['id'], | 
					
						
							|  |  |  |         "object": actor_json['id'], | 
					
						
							|  |  |  |         "target": actor_json['movedTo'], | 
					
						
							|  |  |  |         "to": ['https://www.w3.org/ns/activitystreams#Public'], | 
					
						
							|  |  |  |         "cc": [actor_json['id'] + '/followers'] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def get_default_person_context() -> str: | 
					
						
							| 
									
										
										
										
											2020-08-05 10:33:47 +00:00
										 |  |  |     """Gets the default actor context
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-08-05 10:28:54 +00:00
										 |  |  |     return { | 
					
						
							|  |  |  |         'Curve25519Key': 'toot:Curve25519Key', | 
					
						
							|  |  |  |         'Device': 'toot:Device', | 
					
						
							|  |  |  |         'Ed25519Key': 'toot:Ed25519Key', | 
					
						
							|  |  |  |         'Ed25519Signature': 'toot:Ed25519Signature', | 
					
						
							|  |  |  |         'EncryptedMessage': 'toot:EncryptedMessage', | 
					
						
							| 
									
										
										
										
											2021-01-21 13:17:43 +00:00
										 |  |  |         'IdentityProof': 'toot:IdentityProof', | 
					
						
							|  |  |  |         'PropertyValue': 'schema:PropertyValue', | 
					
						
							|  |  |  |         'alsoKnownAs': {'@id': 'as:alsoKnownAs', '@type': '@id'}, | 
					
						
							|  |  |  |         'cipherText': 'toot:cipherText', | 
					
						
							|  |  |  |         'claim': {'@id': 'toot:claim', '@type': '@id'}, | 
					
						
							|  |  |  |         'deviceId': 'toot:deviceId', | 
					
						
							|  |  |  |         'devices': {'@id': 'toot:devices', '@type': '@id'}, | 
					
						
							|  |  |  |         'discoverable': 'toot:discoverable', | 
					
						
							|  |  |  |         'featured': {'@id': 'toot:featured', '@type': '@id'}, | 
					
						
							|  |  |  |         'featuredTags': {'@id': 'toot:featuredTags', '@type': '@id'}, | 
					
						
							| 
									
										
										
										
											2020-08-05 10:28:54 +00:00
										 |  |  |         'fingerprintKey': {'@id': 'toot:fingerprintKey', '@type': '@id'}, | 
					
						
							| 
									
										
										
										
											2021-01-21 13:17:43 +00:00
										 |  |  |         'focalPoint': {'@container': '@list', '@id': 'toot:focalPoint'}, | 
					
						
							|  |  |  |         'identityKey': {'@id': 'toot:identityKey', '@type': '@id'}, | 
					
						
							|  |  |  |         'manuallyApprovesFollowers': 'as:manuallyApprovesFollowers', | 
					
						
							| 
									
										
										
										
											2023-08-27 09:39:46 +00:00
										 |  |  |         'indexable': 'toot:indexable', | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |         'searchableBy': { | 
					
						
							|  |  |  |             '@id': 'fedibird:searchableBy', | 
					
						
							|  |  |  |             '@type': '@id' | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2023-08-27 09:39:46 +00:00
										 |  |  |         'memorial': 'toot:memorial', | 
					
						
							| 
									
										
										
										
											2020-08-05 10:28:54 +00:00
										 |  |  |         'messageFranking': 'toot:messageFranking', | 
					
						
							| 
									
										
										
										
											2021-01-21 13:17:43 +00:00
										 |  |  |         'messageType': 'toot:messageType', | 
					
						
							|  |  |  |         'movedTo': {'@id': 'as:movedTo', '@type': '@id'}, | 
					
						
							| 
									
										
										
										
											2020-12-17 22:59:11 +00:00
										 |  |  |         'publicKeyBase64': 'toot:publicKeyBase64', | 
					
						
							| 
									
										
										
										
											2022-05-11 14:34:05 +00:00
										 |  |  |         'schema': 'http://schema.org/', | 
					
						
							| 
									
										
										
										
											2021-01-21 13:17:43 +00:00
										 |  |  |         'suspended': 'toot:suspended', | 
					
						
							|  |  |  |         'toot': 'http://joinmastodon.org/ns#', | 
					
						
							| 
									
										
										
										
											2021-05-13 11:14:14 +00:00
										 |  |  |         'value': 'schema:value', | 
					
						
							| 
									
										
										
										
											2021-05-16 10:42:52 +00:00
										 |  |  |         'hasOccupation': 'schema:hasOccupation', | 
					
						
							| 
									
										
										
										
											2021-05-13 19:58:16 +00:00
										 |  |  |         'Occupation': 'schema:Occupation', | 
					
						
							| 
									
										
										
										
											2021-05-16 15:10:39 +00:00
										 |  |  |         'occupationalCategory': 'schema:occupationalCategory', | 
					
						
							|  |  |  |         'Role': 'schema:Role', | 
					
						
							|  |  |  |         'WebSite': 'schema:Project', | 
					
						
							|  |  |  |         'CategoryCode': 'schema:CategoryCode', | 
					
						
							|  |  |  |         'CategoryCodeSet': 'schema:CategoryCodeSet' | 
					
						
							| 
									
										
										
										
											2020-08-05 10:28:54 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def _create_person_base(base_dir: str, nickname: str, domain: str, port: int, | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |                         http_prefix: str, save_to_file: bool, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                         manual_follower_approval: bool, | 
					
						
							|  |  |  |                         group_account: bool, | 
					
						
							|  |  |  |                         password: str) -> (str, str, {}, {}): | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     """Returns the private key, public key, actor and webfinger endpoint
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     private_key_pem, public_key_pem = generate_rsa_key() | 
					
						
							|  |  |  |     webfinger_endpoint = \ | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         create_webfinger_endpoint(nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2024-02-26 13:05:26 +00:00
										 |  |  |                                   http_prefix) | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |     if save_to_file: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         store_webfinger_endpoint(nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                  base_dir, webfinger_endpoint) | 
					
						
							| 
									
										
										
										
											2019-06-30 18:23:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 09:16:03 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     original_domain = domain | 
					
						
							| 
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 |  |  |     domain = get_full_domain(domain, port) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     person_type = 'Person' | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |     if group_account: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         person_type = 'Group' | 
					
						
							| 
									
										
										
										
											2020-07-12 11:58:32 +00:00
										 |  |  |     # Enable follower approval by default | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     approve_followers = manual_follower_approval | 
					
						
							|  |  |  |     person_name = nickname | 
					
						
							|  |  |  |     person_id = local_actor_url(http_prefix, nickname, domain) | 
					
						
							|  |  |  |     inbox_str = person_id + '/inbox' | 
					
						
							|  |  |  |     person_url = http_prefix + '://' + domain + '/@' + person_name | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     if nickname == 'inbox': | 
					
						
							| 
									
										
										
										
											2019-08-23 19:37:40 +00:00
										 |  |  |         # shared inbox | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         inbox_str = http_prefix + '://' + domain + '/actor/inbox' | 
					
						
							|  |  |  |         person_id = http_prefix + '://' + domain + '/actor' | 
					
						
							|  |  |  |         person_url = http_prefix + '://' + domain + \ | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |             '/about/more?instance_actor=true' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         person_name = original_domain | 
					
						
							|  |  |  |         approve_followers = True | 
					
						
							|  |  |  |         person_type = 'Application' | 
					
						
							| 
									
										
										
										
											2020-10-27 16:00:57 +00:00
										 |  |  |     elif nickname == 'news': | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         person_url = http_prefix + '://' + domain + \ | 
					
						
							| 
									
										
										
										
											2020-10-27 16:00:57 +00:00
										 |  |  |             '/about/more?news_actor=true' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         approve_followers = True | 
					
						
							|  |  |  |         person_type = 'Application' | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 15:09:27 +00:00
										 |  |  |     # NOTE: these image files don't need to have | 
					
						
							|  |  |  |     # cryptographically secure names | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     image_url = \ | 
					
						
							|  |  |  |         person_id + '/image' + \ | 
					
						
							| 
									
										
										
										
											2020-07-08 15:17:00 +00:00
										 |  |  |         str(randint(10000000000000, 99999999999999)) + '.png'  # nosec | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     icon_url = \ | 
					
						
							|  |  |  |         person_id + '/avatar' + \ | 
					
						
							| 
									
										
										
										
											2020-07-08 15:17:00 +00:00
										 |  |  |         str(randint(10000000000000, 99999999999999)) + '.png'  # nosec | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     _, published = get_status_number() | 
					
						
							|  |  |  |     new_person = { | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |         '@context': [ | 
					
						
							|  |  |  |             'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |             'https://w3id.org/security/v1', | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  |             get_default_person_context() | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |         ], | 
					
						
							| 
									
										
										
										
											2021-05-08 17:13:46 +00:00
										 |  |  |         'published': published, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'alsoKnownAs': [], | 
					
						
							| 
									
										
										
										
											2021-01-21 13:17:43 +00:00
										 |  |  |         'attachment': [], | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         'devices': person_id + '/collections/devices', | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'endpoints': { | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             'id': person_id + '/endpoints', | 
					
						
							| 
									
										
										
										
											2021-12-25 17:09:22 +00:00
										 |  |  |             'sharedInbox': http_prefix + '://' + domain + '/inbox', | 
					
						
							| 
									
										
										
										
											2023-06-27 18:21:56 +00:00
										 |  |  |             'offers': person_id + '/offers', | 
					
						
							| 
									
										
										
										
											2023-07-11 11:15:27 +00:00
										 |  |  |             'wanted': person_id + '/wanted', | 
					
						
							|  |  |  |             'blocked': person_id + '/blocked', | 
					
						
							|  |  |  |             'pendingFollowers': person_id + '/pendingFollowers' | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         'featured': person_id + '/collections/featured', | 
					
						
							|  |  |  |         'featuredTags': person_id + '/collections/tags', | 
					
						
							|  |  |  |         'followers': person_id + '/followers', | 
					
						
							|  |  |  |         'following': person_id + '/following', | 
					
						
							|  |  |  |         'tts': person_id + '/speaker', | 
					
						
							|  |  |  |         'shares': person_id + '/catalog', | 
					
						
							| 
									
										
										
										
											2021-05-16 15:10:39 +00:00
										 |  |  |         'hasOccupation': [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 '@type': 'Occupation', | 
					
						
							|  |  |  |                 'name': "", | 
					
						
							| 
									
										
										
										
											2021-05-17 10:27:14 +00:00
										 |  |  |                 "occupationLocation": { | 
					
						
							|  |  |  |                     "@type": "City", | 
					
						
							|  |  |  |                     "name": "Fediverse" | 
					
						
							| 
									
										
										
										
											2021-05-17 09:12:10 +00:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2021-05-16 15:10:39 +00:00
										 |  |  |                 'skills': [] | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'availability': None, | 
					
						
							|  |  |  |         'icon': { | 
					
						
							|  |  |  |             'mediaType': 'image/png', | 
					
						
							|  |  |  |             'type': 'Image', | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             'url': icon_url | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         'id': person_id, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'image': { | 
					
						
							|  |  |  |             'mediaType': 'image/png', | 
					
						
							|  |  |  |             'type': 'Image', | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             'url': image_url | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         'inbox': inbox_str, | 
					
						
							|  |  |  |         'manuallyApprovesFollowers': approve_followers, | 
					
						
							| 
									
										
										
										
											2024-05-16 11:50:12 +00:00
										 |  |  |         'capabilities': { | 
					
						
							|  |  |  |             'acceptsChatMessages': False, | 
					
						
							|  |  |  |             'supportsFriendRequests': False | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2021-01-21 13:17:43 +00:00
										 |  |  |         'discoverable': True, | 
					
						
							| 
									
										
										
										
											2023-08-27 09:30:20 +00:00
										 |  |  |         'indexable': False, | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |         'searchableBy': [], | 
					
						
							| 
									
										
										
										
											2023-08-27 09:30:20 +00:00
										 |  |  |         'memorial': False, | 
					
						
							| 
									
										
										
										
											2023-12-24 15:53:11 +00:00
										 |  |  |         'hideFollows': False, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         'name': person_name, | 
					
						
							|  |  |  |         'outbox': person_id + '/outbox', | 
					
						
							|  |  |  |         'preferredUsername': person_name, | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'summary': '', | 
					
						
							|  |  |  |         'publicKey': { | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             'id': person_id + '#main-key', | 
					
						
							|  |  |  |             'owner': person_id, | 
					
						
							|  |  |  |             'publicKeyPem': public_key_pem | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         }, | 
					
						
							|  |  |  |         'tag': [], | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         'type': person_type, | 
					
						
							| 
									
										
										
										
											2024-01-07 13:45:53 +00:00
										 |  |  |         'url': person_url, | 
					
						
							|  |  |  |         'vcard:Address': '', | 
					
						
							|  |  |  |         'vcard:bday': '' | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-17 09:37:48 +00:00
										 |  |  |     # extra fields used only by groups | 
					
						
							|  |  |  |     if group_account: | 
					
						
							|  |  |  |         new_person['postingRestrictedToMods'] = False | 
					
						
							|  |  |  |         new_person['moderators'] = person_id + '/moderators' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     if nickname == 'inbox': | 
					
						
							| 
									
										
										
										
											2019-08-23 19:47:03 +00:00
										 |  |  |         # fields not needed by the shared inbox | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         del new_person['outbox'] | 
					
						
							|  |  |  |         del new_person['icon'] | 
					
						
							|  |  |  |         del new_person['image'] | 
					
						
							|  |  |  |         if new_person.get('skills'): | 
					
						
							|  |  |  |             del new_person['skills'] | 
					
						
							|  |  |  |         del new_person['shares'] | 
					
						
							|  |  |  |         if new_person.get('roles'): | 
					
						
							|  |  |  |             del new_person['roles'] | 
					
						
							|  |  |  |         del new_person['tag'] | 
					
						
							|  |  |  |         del new_person['availability'] | 
					
						
							|  |  |  |         del new_person['followers'] | 
					
						
							|  |  |  |         del new_person['following'] | 
					
						
							|  |  |  |         del new_person['attachment'] | 
					
						
							| 
									
										
										
										
											2019-08-23 19:47:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |     if save_to_file: | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |         # save person to file | 
					
						
							| 
									
										
										
										
											2024-05-12 18:32:50 +00:00
										 |  |  |         if not os.path.isdir(base_dir): | 
					
						
							|  |  |  |             os.mkdir(base_dir) | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |         people_subdir = data_dir(base_dir) | 
					
						
							|  |  |  |         if not os.path.isdir(people_subdir): | 
					
						
							|  |  |  |             os.mkdir(people_subdir) | 
					
						
							|  |  |  |         if not os.path.isdir(people_subdir + '/' + handle): | 
					
						
							|  |  |  |             os.mkdir(people_subdir + '/' + handle) | 
					
						
							|  |  |  |         if not os.path.isdir(people_subdir + '/' + | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                              handle + '/inbox'): | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |             os.mkdir(people_subdir + '/' + handle + '/inbox') | 
					
						
							|  |  |  |         if not os.path.isdir(people_subdir + '/' + | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |                              handle + '/outbox'): | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |             os.mkdir(people_subdir + '/' + handle + '/outbox') | 
					
						
							|  |  |  |         if not os.path.isdir(people_subdir + '/' + | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                              handle + '/queue'): | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |             os.mkdir(people_subdir + '/' + handle + '/queue') | 
					
						
							|  |  |  |         filename = people_subdir + '/' + handle + '.json' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         save_json(new_person, filename) | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-22 14:43:43 +00:00
										 |  |  |         # save to cache | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |         if not os.path.isdir(base_dir + '/cache'): | 
					
						
							|  |  |  |             os.mkdir(base_dir + '/cache') | 
					
						
							|  |  |  |         if not os.path.isdir(base_dir + '/cache/actors'): | 
					
						
							|  |  |  |             os.mkdir(base_dir + '/cache/actors') | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         cache_filename = base_dir + '/cache/actors/' + \ | 
					
						
							|  |  |  |             new_person['id'].replace('/', '#') + '.json' | 
					
						
							|  |  |  |         save_json(new_person, cache_filename) | 
					
						
							| 
									
										
										
										
											2019-08-22 14:43:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |         # save the private key | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         private_keys_subdir = '/keys/private' | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |         if not os.path.isdir(base_dir + '/keys'): | 
					
						
							|  |  |  |             os.mkdir(base_dir + '/keys') | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if not os.path.isdir(base_dir + private_keys_subdir): | 
					
						
							|  |  |  |             os.mkdir(base_dir + private_keys_subdir) | 
					
						
							|  |  |  |         filename = base_dir + private_keys_subdir + '/' + handle + '.key' | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2024-07-14 13:01:46 +00:00
										 |  |  |             with open(filename, 'w+', encoding='utf-8') as fp_text: | 
					
						
							|  |  |  |                 print(private_key_pem, file=fp_text) | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: _create_person_base unable to save ' + filename) | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # save the public key | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         public_keys_subdir = '/keys/public' | 
					
						
							|  |  |  |         if not os.path.isdir(base_dir + public_keys_subdir): | 
					
						
							|  |  |  |             os.mkdir(base_dir + public_keys_subdir) | 
					
						
							|  |  |  |         filename = base_dir + public_keys_subdir + '/' + handle + '.pem' | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2024-07-14 13:01:46 +00:00
										 |  |  |             with open(filename, 'w+', encoding='utf-8') as fp_text: | 
					
						
							|  |  |  |                 print(public_key_pem, file=fp_text) | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: _create_person_base unable to save 2 ' + filename) | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-03 19:10:24 +00:00
										 |  |  |         if password: | 
					
						
							| 
									
										
										
										
											2022-06-21 13:35:35 +00:00
										 |  |  |             password = remove_eol(password).strip() | 
					
						
							| 
									
										
										
										
											2021-12-28 21:36:27 +00:00
										 |  |  |             store_basic_credentials(base_dir, nickname, password) | 
					
						
							| 
									
										
										
										
											2019-07-03 19:10:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     return private_key_pem, public_key_pem, new_person, webfinger_endpoint | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def register_account(base_dir: str, http_prefix: str, domain: str, port: int, | 
					
						
							|  |  |  |                      nickname: str, password: str, | 
					
						
							|  |  |  |                      manual_follower_approval: bool) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-08 13:38:33 +00:00
										 |  |  |     """Registers a new account from the web interface
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |     if _account_exists(base_dir, nickname, domain): | 
					
						
							| 
									
										
										
										
											2019-08-09 16:33:45 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-28 14:41:10 +00:00
										 |  |  |     if not valid_nickname(domain, nickname): | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |         print('REGISTER: Nickname ' + nickname + ' is invalid') | 
					
						
							| 
									
										
										
										
											2019-08-08 13:38:33 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     if len(password) < 8: | 
					
						
							| 
									
										
										
										
											2019-08-08 13:38:33 +00:00
										 |  |  |         print('REGISTER: Password should be at least 8 characters') | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     (private_key_pem, _, | 
					
						
							|  |  |  |      _, _) = create_person(base_dir, nickname, | 
					
						
							|  |  |  |                            domain, port, | 
					
						
							|  |  |  |                            http_prefix, True, | 
					
						
							|  |  |  |                            manual_follower_approval, | 
					
						
							|  |  |  |                            password) | 
					
						
							|  |  |  |     if private_key_pem: | 
					
						
							| 
									
										
										
										
											2019-08-08 13:38:33 +00:00
										 |  |  |         return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def create_group(base_dir: str, nickname: str, domain: str, port: int, | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |                  http_prefix: str, save_to_file: bool, | 
					
						
							| 
									
										
										
										
											2024-02-19 15:38:08 +00:00
										 |  |  |                  password: str) -> (str, str, {}, {}): | 
					
						
							| 
									
										
										
										
											2019-10-04 12:39:46 +00:00
										 |  |  |     """Returns a group
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     (private_key_pem, public_key_pem, | 
					
						
							|  |  |  |      new_person, webfinger_endpoint) = create_person(base_dir, nickname, | 
					
						
							|  |  |  |                                                      domain, port, | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |                                                      http_prefix, save_to_file, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                                      False, password, True) | 
					
						
							| 
									
										
										
										
											2021-07-30 10:51:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     return private_key_pem, public_key_pem, new_person, webfinger_endpoint | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 11:42:24 +00:00
										 |  |  | def clear_person_qrcodes(base_dir: str) -> None: | 
					
						
							|  |  |  |     """Clears qrcodes for all accounts
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |     dir_str = data_dir(base_dir) | 
					
						
							|  |  |  |     for _, dirs, _ in os.walk(dir_str): | 
					
						
							| 
									
										
										
										
											2022-03-22 11:42:24 +00:00
										 |  |  |         for handle in dirs: | 
					
						
							|  |  |  |             if '@' not in handle: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             nickname = handle.split('@')[0] | 
					
						
							|  |  |  |             domain = handle.split('@')[1] | 
					
						
							|  |  |  |             qrcode_filename = \ | 
					
						
							|  |  |  |                 acct_dir(base_dir, nickname, domain) + '/qrcode.png' | 
					
						
							|  |  |  |             if os.path.isfile(qrcode_filename): | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     os.remove(qrcode_filename) | 
					
						
							|  |  |  |                 except OSError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |             if os.path.isfile(qrcode_filename + '.etag'): | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     os.remove(qrcode_filename + '.etag') | 
					
						
							|  |  |  |                 except OSError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |         break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def save_person_qrcode(base_dir: str, | 
					
						
							| 
									
										
										
										
											2022-03-22 10:32:31 +00:00
										 |  |  |                        nickname: str, domain: str, qrcode_domain: str, | 
					
						
							|  |  |  |                        port: int, scale=6) -> None: | 
					
						
							| 
									
										
										
										
											2020-06-21 16:02:52 +00:00
										 |  |  |     """Saves a qrcode image for the handle of the person
 | 
					
						
							|  |  |  |     This helps to transfer onion or i2p handles to a mobile device | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     qrcode_filename = acct_dir(base_dir, nickname, domain) + '/qrcode.png' | 
					
						
							|  |  |  |     if os.path.isfile(qrcode_filename): | 
					
						
							| 
									
										
										
										
											2020-06-21 16:02:52 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2022-03-22 10:32:31 +00:00
										 |  |  |     handle = get_full_domain('@' + nickname + '@' + qrcode_domain, port) | 
					
						
							| 
									
										
										
										
											2020-06-21 16:02:52 +00:00
										 |  |  |     url = pyqrcode.create(handle) | 
					
						
							| 
									
										
										
										
											2022-09-10 09:24:13 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         url.png(qrcode_filename, scale) | 
					
						
							|  |  |  |     except ModuleNotFoundError: | 
					
						
							|  |  |  |         print('EX: pyqrcode png module not found') | 
					
						
							| 
									
										
										
										
											2020-06-21 16:02:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def create_person(base_dir: str, nickname: str, domain: str, port: int, | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |                   http_prefix: str, save_to_file: bool, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                   manual_follower_approval: bool, | 
					
						
							|  |  |  |                   password: str, | 
					
						
							|  |  |  |                   group_account: bool = False) -> (str, str, {}, {}): | 
					
						
							| 
									
										
										
										
											2019-07-05 11:27:18 +00:00
										 |  |  |     """Returns the private key, public key, actor and webfinger endpoint
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-28 14:41:10 +00:00
										 |  |  |     if not valid_nickname(domain, nickname): | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |         return None, None, None, None | 
					
						
							| 
									
										
										
										
											2019-08-08 10:50:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-09 09:14:31 +00:00
										 |  |  |     # If a config.json file doesn't exist then don't decrement | 
					
						
							|  |  |  |     # remaining registrations counter | 
					
						
							| 
									
										
										
										
											2020-11-24 12:42:33 +00:00
										 |  |  |     if nickname != 'news': | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         remaining_config_exists = \ | 
					
						
							| 
									
										
										
										
											2021-12-26 14:08:58 +00:00
										 |  |  |             get_config_param(base_dir, 'registrationsRemaining') | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if remaining_config_exists: | 
					
						
							|  |  |  |             registrations_remaining = int(remaining_config_exists) | 
					
						
							|  |  |  |             if registrations_remaining <= 0: | 
					
						
							| 
									
										
										
										
											2020-11-24 12:42:33 +00:00
										 |  |  |                 return None, None, None, None | 
					
						
							|  |  |  |     else: | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |         dir_str = data_dir(base_dir) | 
					
						
							|  |  |  |         if os.path.isdir(dir_str + '/news@' + domain): | 
					
						
							| 
									
										
										
										
											2020-11-24 12:42:33 +00:00
										 |  |  |             # news account already exists | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |             return None, None, None, None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-25 21:42:26 +00:00
										 |  |  |     manual_follower = manual_follower_approval | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     (private_key_pem, public_key_pem, | 
					
						
							|  |  |  |      new_person, webfinger_endpoint) = _create_person_base(base_dir, nickname, | 
					
						
							|  |  |  |                                                            domain, port, | 
					
						
							|  |  |  |                                                            http_prefix, | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |                                                            save_to_file, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                                            manual_follower, | 
					
						
							|  |  |  |                                                            group_account, | 
					
						
							|  |  |  |                                                            password) | 
					
						
							| 
									
										
										
										
											2021-12-26 14:08:58 +00:00
										 |  |  |     if not get_config_param(base_dir, 'admin'): | 
					
						
							| 
									
										
										
										
											2020-11-24 12:42:33 +00:00
										 |  |  |         if nickname != 'news': | 
					
						
							|  |  |  |             # print(nickname+' becomes the instance admin and a moderator') | 
					
						
							| 
									
										
										
										
											2021-12-27 20:38:02 +00:00
										 |  |  |             set_config_param(base_dir, 'admin', nickname) | 
					
						
							| 
									
										
										
										
											2021-12-28 22:22:09 +00:00
										 |  |  |             set_role(base_dir, nickname, domain, 'admin') | 
					
						
							|  |  |  |             set_role(base_dir, nickname, domain, 'moderator') | 
					
						
							|  |  |  |             set_role(base_dir, nickname, domain, 'editor') | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |     dir_str = data_dir(base_dir) | 
					
						
							|  |  |  |     if not os.path.isdir(dir_str): | 
					
						
							|  |  |  |         os.mkdir(dir_str) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |     if not os.path.isdir(account_dir): | 
					
						
							|  |  |  |         os.mkdir(account_dir) | 
					
						
							| 
									
										
										
										
											2020-08-29 11:14:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-25 21:42:26 +00:00
										 |  |  |     if manual_follower_approval: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         follow_dms_filename = \ | 
					
						
							| 
									
										
										
										
											2021-12-26 12:02:29 +00:00
										 |  |  |             acct_dir(base_dir, nickname, domain) + '/.followDMs' | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2024-07-16 12:20:58 +00:00
										 |  |  |             with open(follow_dms_filename, 'w+', encoding='utf-8') as fp_foll: | 
					
						
							|  |  |  |                 fp_foll.write('\n') | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: create_person unable to write ' + follow_dms_filename) | 
					
						
							| 
									
										
										
										
											2020-07-12 13:28:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-27 09:23:21 +00:00
										 |  |  |     # notify when posts are liked | 
					
						
							| 
									
										
										
										
											2020-11-24 12:42:33 +00:00
										 |  |  |     if nickname != 'news': | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         notify_likes_filename = \ | 
					
						
							| 
									
										
										
										
											2021-12-26 12:02:29 +00:00
										 |  |  |             acct_dir(base_dir, nickname, domain) + '/.notifyLikes' | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2024-07-16 12:20:58 +00:00
										 |  |  |             with open(notify_likes_filename, 'w+', encoding='utf-8') as fp_lik: | 
					
						
							|  |  |  |                 fp_lik.write('\n') | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: create_person unable to write 2 ' + | 
					
						
							|  |  |  |                   notify_likes_filename) | 
					
						
							| 
									
										
										
										
											2020-11-24 12:42:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-10 19:33:28 +00:00
										 |  |  |     # notify when posts have emoji reactions | 
					
						
							|  |  |  |     if nickname != 'news': | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         notify_reactions_filename = \ | 
					
						
							| 
									
										
										
										
											2021-12-26 12:02:29 +00:00
										 |  |  |             acct_dir(base_dir, nickname, domain) + '/.notifyReactions' | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |             with open(notify_reactions_filename, 'w+', | 
					
						
							| 
									
										
										
										
											2024-07-16 12:20:58 +00:00
										 |  |  |                       encoding='utf-8') as fp_notify: | 
					
						
							|  |  |  |                 fp_notify.write('\n') | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: create_person unable to write 3 ' + | 
					
						
							|  |  |  |                   notify_reactions_filename) | 
					
						
							| 
									
										
										
										
											2021-11-10 19:33:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 14:08:58 +00:00
										 |  |  |     theme = get_config_param(base_dir, 'theme') | 
					
						
							| 
									
										
										
										
											2020-11-14 12:02:12 +00:00
										 |  |  |     if not theme: | 
					
						
							|  |  |  |         theme = 'default' | 
					
						
							| 
									
										
										
										
											2020-11-24 12:42:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if nickname != 'news': | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |         if os.path.isfile(base_dir + '/img/default-avatar.png'): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |             copyfile(base_dir + '/img/default-avatar.png', | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                      account_dir + '/avatar.png') | 
					
						
							| 
									
										
										
										
											2020-11-24 12:42:33 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         news_avatar = base_dir + '/theme/' + theme + '/icons/avatar_news.png' | 
					
						
							|  |  |  |         if os.path.isfile(news_avatar): | 
					
						
							|  |  |  |             account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |             copyfile(news_avatar, account_dir + '/avatar.png') | 
					
						
							| 
									
										
										
										
											2020-11-24 12:42:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     default_profile_image_filename = base_dir + '/theme/default/image.png' | 
					
						
							| 
									
										
										
										
											2019-09-12 12:24:13 +00:00
										 |  |  |     if theme: | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |         if os.path.isfile(base_dir + '/theme/' + theme + '/image.png'): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             default_profile_image_filename = \ | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                 base_dir + '/theme/' + theme + '/image.png' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if os.path.isfile(default_profile_image_filename): | 
					
						
							|  |  |  |         account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |         copyfile(default_profile_image_filename, account_dir + '/image.png') | 
					
						
							|  |  |  |     default_banner_filename = base_dir + '/theme/default/banner.png' | 
					
						
							| 
									
										
										
										
											2019-09-12 12:24:13 +00:00
										 |  |  |     if theme: | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |         if os.path.isfile(base_dir + '/theme/' + theme + '/banner.png'): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             default_banner_filename = \ | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                 base_dir + '/theme/' + theme + '/banner.png' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if os.path.isfile(default_banner_filename): | 
					
						
							|  |  |  |         account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |         copyfile(default_banner_filename, account_dir + '/banner.png') | 
					
						
							|  |  |  |     if nickname != 'news' and remaining_config_exists: | 
					
						
							|  |  |  |         registrations_remaining -= 1 | 
					
						
							| 
									
										
										
										
											2021-12-27 20:38:02 +00:00
										 |  |  |         set_config_param(base_dir, 'registrationsRemaining', | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                          str(registrations_remaining)) | 
					
						
							| 
									
										
										
										
											2022-03-22 10:32:31 +00:00
										 |  |  |     save_person_qrcode(base_dir, nickname, domain, domain, port) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     return private_key_pem, public_key_pem, new_person, webfinger_endpoint | 
					
						
							| 
									
										
										
										
											2019-07-05 11:27:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def create_shared_inbox(base_dir: str, nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                         http_prefix: str) -> (str, str, {}, {}): | 
					
						
							| 
									
										
										
										
											2019-07-05 11:27:18 +00:00
										 |  |  |     """Generates the shared inbox
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |     return _create_person_base(base_dir, nickname, domain, port, http_prefix, | 
					
						
							|  |  |  |                                True, True, False, None) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-05 21:24:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def create_news_inbox(base_dir: str, domain: str, port: int, | 
					
						
							|  |  |  |                       http_prefix: str) -> (str, str, {}, {}): | 
					
						
							| 
									
										
										
										
											2020-10-07 16:01:45 +00:00
										 |  |  |     """Generates the news inbox
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |     return create_person(base_dir, 'news', domain, port, | 
					
						
							|  |  |  |                          http_prefix, True, True, None) | 
					
						
							| 
									
										
										
										
											2020-10-07 16:01:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  | def person_upgrade_actor(base_dir: str, person_json: {}, | 
					
						
							| 
									
										
										
										
											2022-06-12 12:30:14 +00:00
										 |  |  |                          filename: str) -> None: | 
					
						
							| 
									
										
										
										
											2020-01-19 20:29:39 +00:00
										 |  |  |     """Alter the actor to add any new properties
 | 
					
						
							| 
									
										
										
										
											2020-01-19 20:43:03 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     update_actor = False | 
					
						
							| 
									
										
										
										
											2020-01-19 20:43:03 +00:00
										 |  |  |     if not os.path.isfile(filename): | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |         print('WARN: actor file not found ' + filename) | 
					
						
							| 
									
										
										
										
											2020-01-19 20:43:03 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not person_json: | 
					
						
							|  |  |  |         person_json = load_json(filename) | 
					
						
							| 
									
										
										
										
											2020-01-19 20:58:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-17 10:02:20 +00:00
										 |  |  |     # add extra group fields | 
					
						
							|  |  |  |     if person_json.get('type') and person_json.get('id'): | 
					
						
							|  |  |  |         if person_json['type'] == 'Group': | 
					
						
							|  |  |  |             person_json['postingRestrictedToMods'] = False | 
					
						
							|  |  |  |             person_id = person_json['id'] | 
					
						
							|  |  |  |             person_json['moderators'] = person_id + '/moderators' | 
					
						
							|  |  |  |             update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-16 09:02:33 +00:00
										 |  |  |     if 'capabilities' not in person_json: | 
					
						
							| 
									
										
										
										
											2024-05-16 11:50:12 +00:00
										 |  |  |         person_json['capabilities'] = { | 
					
						
							|  |  |  |             'acceptsChatMessages': False, | 
					
						
							|  |  |  |             'supportsFriendRequests': False | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-05-16 09:02:33 +00:00
										 |  |  |         update_actor = True | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         if 'acceptsChatMessages' not in person_json['capabilities']: | 
					
						
							|  |  |  |             person_json['capabilities']['acceptsChatMessages'] = False | 
					
						
							|  |  |  |             update_actor = True | 
					
						
							| 
									
										
										
										
											2024-05-16 11:50:12 +00:00
										 |  |  |         if 'supportsFriendRequests' not in person_json['capabilities']: | 
					
						
							|  |  |  |             person_json['capabilities']['supportsFriendRequests'] = False | 
					
						
							|  |  |  |             update_actor = True | 
					
						
							| 
									
										
										
										
											2024-05-16 09:02:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |     if 'memorial' not in person_json: | 
					
						
							| 
									
										
										
										
											2023-08-27 09:30:20 +00:00
										 |  |  |         person_json['memorial'] = False | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |     if 'hideFollows' not in person_json: | 
					
						
							| 
									
										
										
										
											2023-12-24 15:53:11 +00:00
										 |  |  |         person_json['hideFollows'] = False | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |     if 'indexable' not in person_json: | 
					
						
							| 
									
										
										
										
											2023-08-27 09:30:20 +00:00
										 |  |  |         person_json['indexable'] = False | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-07 13:45:53 +00:00
										 |  |  |     if 'vcard:Address' not in person_json: | 
					
						
							|  |  |  |         person_json['vcard:Address'] = '' | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'vcard:bday' not in person_json: | 
					
						
							|  |  |  |         person_json['vcard:bday'] = '' | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |     if 'searchableBy' not in person_json: | 
					
						
							| 
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 |  |  |         person_json['searchableBy']: list[str] = [] | 
					
						
							| 
									
										
										
										
											2024-01-06 11:53:05 +00:00
										 |  |  |         update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-08 17:13:46 +00:00
										 |  |  |     # add a speaker endpoint | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not person_json.get('tts'): | 
					
						
							|  |  |  |         person_json['tts'] = person_json['id'] + '/speaker' | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not person_json.get('published'): | 
					
						
							|  |  |  |         _, published = get_status_number() | 
					
						
							|  |  |  |         person_json['published'] = published | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-27 18:21:56 +00:00
										 |  |  |     if person_json.get('endpoints'): | 
					
						
							| 
									
										
										
										
											2023-07-11 11:15:27 +00:00
										 |  |  |         if not person_json['endpoints'].get('pendingFollowers'): | 
					
						
							|  |  |  |             person_json['endpoints']['pendingFollowers'] = \ | 
					
						
							|  |  |  |                 person_json['id'] + '/pendingFollowers' | 
					
						
							|  |  |  |             update_actor = True | 
					
						
							| 
									
										
										
										
											2023-07-05 11:17:25 +00:00
										 |  |  |         if not person_json['endpoints'].get('blocked'): | 
					
						
							| 
									
										
										
										
											2023-07-05 11:56:02 +00:00
										 |  |  |             person_json['endpoints']['blocked'] = \ | 
					
						
							|  |  |  |                 person_json['id'] + '/blocked' | 
					
						
							| 
									
										
										
										
											2023-07-05 11:17:25 +00:00
										 |  |  |             update_actor = True | 
					
						
							| 
									
										
										
										
											2023-06-27 18:21:56 +00:00
										 |  |  |         if not person_json['endpoints'].get('offers'): | 
					
						
							|  |  |  |             person_json['endpoints']['offers'] = person_json['id'] + '/offers' | 
					
						
							|  |  |  |             update_actor = True | 
					
						
							|  |  |  |         if not person_json['endpoints'].get('wanted'): | 
					
						
							|  |  |  |             person_json['endpoints']['wanted'] = person_json['id'] + '/wanted' | 
					
						
							|  |  |  |             update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if person_json.get('shares'): | 
					
						
							|  |  |  |         if person_json['shares'].endswith('/shares'): | 
					
						
							|  |  |  |             person_json['shares'] = person_json['id'] + '/catalog' | 
					
						
							|  |  |  |             update_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     occupation_name = '' | 
					
						
							|  |  |  |     if person_json.get('occupationName'): | 
					
						
							|  |  |  |         occupation_name = person_json['occupationName'] | 
					
						
							|  |  |  |         del person_json['occupationName'] | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							|  |  |  |     if person_json.get('occupation'): | 
					
						
							|  |  |  |         occupation_name = person_json['occupation'] | 
					
						
							|  |  |  |         del person_json['occupation'] | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							| 
									
										
										
										
											2021-05-13 11:14:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-13 20:21:37 +00:00
										 |  |  |     # if the older skills format is being used then switch | 
					
						
							|  |  |  |     # to the new one | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not person_json.get('hasOccupation'): | 
					
						
							|  |  |  |         person_json['hasOccupation'] = [{ | 
					
						
							| 
									
										
										
										
											2021-07-04 11:39:13 +00:00
										 |  |  |             '@type': 'Occupation', | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             'name': occupation_name, | 
					
						
							| 
									
										
										
										
											2021-07-04 11:39:13 +00:00
										 |  |  |             "occupationLocation": { | 
					
						
							|  |  |  |                 "@type": "City", | 
					
						
							|  |  |  |                 "name": "Fediverse" | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             'skills': [] | 
					
						
							|  |  |  |         }] | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         update_actor = True | 
					
						
							| 
									
										
										
										
											2021-05-14 18:02:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-13 20:21:37 +00:00
										 |  |  |     # remove the old skills format | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if person_json.get('skills'): | 
					
						
							|  |  |  |         del person_json['skills'] | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							| 
									
										
										
										
											2021-05-13 13:27:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-13 20:21:37 +00:00
										 |  |  |     # if the older roles format is being used then switch | 
					
						
							|  |  |  |     # to the new one | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if person_json.get('affiliation'): | 
					
						
							|  |  |  |         del person_json['affiliation'] | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							| 
									
										
										
										
											2021-05-13 19:58:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not isinstance(person_json['hasOccupation'], list): | 
					
						
							|  |  |  |         person_json['hasOccupation'] = [{ | 
					
						
							| 
									
										
										
										
											2021-07-04 11:39:13 +00:00
										 |  |  |             '@type': 'Occupation', | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             'name': occupation_name, | 
					
						
							| 
									
										
										
										
											2021-07-04 11:39:13 +00:00
										 |  |  |             'occupationLocation': { | 
					
						
							|  |  |  |                 '@type': 'City', | 
					
						
							|  |  |  |                 'name': 'Fediverse' | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             'skills': [] | 
					
						
							|  |  |  |         }] | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         update_actor = True | 
					
						
							| 
									
										
										
										
											2021-05-17 09:28:15 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         # add location if it is missing | 
					
						
							| 
									
										
										
										
											2022-01-08 10:58:54 +00:00
										 |  |  |         for index, _ in enumerate(person_json['hasOccupation']): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             oc_item = person_json['hasOccupation'][index] | 
					
						
							|  |  |  |             if oc_item.get('hasOccupation'): | 
					
						
							|  |  |  |                 oc_item = oc_item['hasOccupation'] | 
					
						
							|  |  |  |             if oc_item.get('location'): | 
					
						
							|  |  |  |                 del oc_item['location'] | 
					
						
							|  |  |  |                 update_actor = True | 
					
						
							|  |  |  |             if not oc_item.get('occupationLocation'): | 
					
						
							|  |  |  |                 oc_item['occupationLocation'] = { | 
					
						
							| 
									
										
										
										
											2021-05-17 10:27:14 +00:00
										 |  |  |                     "@type": "City", | 
					
						
							|  |  |  |                     "name": "Fediverse" | 
					
						
							| 
									
										
										
										
											2021-05-17 09:28:15 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 update_actor = True | 
					
						
							| 
									
										
										
										
											2021-05-17 10:29:07 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 if oc_item['occupationLocation']['@type'] != 'City': | 
					
						
							|  |  |  |                     oc_item['occupationLocation'] = { | 
					
						
							| 
									
										
										
										
											2021-05-17 10:29:07 +00:00
										 |  |  |                         "@type": "City", | 
					
						
							|  |  |  |                         "name": "Fediverse" | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     update_actor = True | 
					
						
							| 
									
										
										
										
											2021-05-14 18:02:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-13 20:21:37 +00:00
										 |  |  |     # if no roles are defined then ensure that the admin | 
					
						
							|  |  |  |     # roles are configured | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     roles_list = get_actor_roles_list(person_json) | 
					
						
							|  |  |  |     if not roles_list: | 
					
						
							| 
									
										
										
										
											2021-12-26 14:11:30 +00:00
										 |  |  |         admin_name = get_config_param(base_dir, 'admin') | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if person_json['id'].endswith('/users/' + admin_name): | 
					
						
							|  |  |  |             roles_list = ["admin", "moderator", "editor"] | 
					
						
							| 
									
										
										
										
											2022-09-02 18:06:13 +00:00
										 |  |  |             actor_roles_from_list(person_json, roles_list) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             update_actor = True | 
					
						
							| 
									
										
										
										
											2021-05-13 20:21:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # remove the old roles format | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if person_json.get('roles'): | 
					
						
							|  |  |  |         del person_json['roles'] | 
					
						
							|  |  |  |         update_actor = True | 
					
						
							| 
									
										
										
										
											2021-05-13 19:58:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if update_actor: | 
					
						
							|  |  |  |         person_json['@context'] = [ | 
					
						
							| 
									
										
										
										
											2021-05-13 11:14:14 +00:00
										 |  |  |             'https://www.w3.org/ns/activitystreams', | 
					
						
							|  |  |  |             'https://w3id.org/security/v1', | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  |             get_default_person_context() | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         ] | 
					
						
							| 
									
										
										
										
											2021-05-13 11:14:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         save_json(person_json, filename) | 
					
						
							| 
									
										
										
										
											2020-01-19 20:58:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # also update the actor within the cache | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         actor_cache_filename = \ | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |             data_dir(base_dir) + '/cache/actors/' + \ | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             person_json['id'].replace('/', '#') + '.json' | 
					
						
							|  |  |  |         if os.path.isfile(actor_cache_filename): | 
					
						
							|  |  |  |             save_json(person_json, actor_cache_filename) | 
					
						
							| 
									
										
										
										
											2020-01-19 20:58:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # update domain/@nickname in actors cache | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         actor_cache_filename = \ | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |             data_dir(base_dir) + '/cache/actors/' + \ | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             replace_users_with_at(person_json['id']).replace('/', '#') + \ | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |             '.json' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if os.path.isfile(actor_cache_filename): | 
					
						
							|  |  |  |             save_json(person_json, actor_cache_filename) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 20:29:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 15:51:12 +00:00
										 |  |  | def add_alternate_domains(actor_json: {}, domain: str, | 
					
						
							|  |  |  |                           onion_domain: str, i2p_domain: str) -> None: | 
					
						
							|  |  |  |     """Adds alternate onion and/or i2p domains to alsoKnownAs
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not onion_domain and not i2p_domain: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not actor_json.get('id'): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if domain not in actor_json['id']: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     nickname = get_nickname_from_actor(actor_json['id']) | 
					
						
							|  |  |  |     if not nickname: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if 'alsoKnownAs' not in actor_json: | 
					
						
							| 
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 |  |  |         actor_json['alsoKnownAs']: list[str] = [] | 
					
						
							| 
									
										
										
										
											2022-03-14 15:51:12 +00:00
										 |  |  |     if onion_domain: | 
					
						
							|  |  |  |         onion_actor = 'http://' + onion_domain + '/users/' + nickname | 
					
						
							|  |  |  |         if onion_actor not in actor_json['alsoKnownAs']: | 
					
						
							|  |  |  |             actor_json['alsoKnownAs'].append(onion_actor) | 
					
						
							|  |  |  |     if i2p_domain: | 
					
						
							|  |  |  |         i2p_actor = 'http://' + i2p_domain + '/users/' + nickname | 
					
						
							|  |  |  |         if i2p_actor not in actor_json['alsoKnownAs']: | 
					
						
							|  |  |  |             actor_json['alsoKnownAs'].append(i2p_actor) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def person_lookup(domain: str, path: str, base_dir: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-03 09:40:27 +00:00
										 |  |  |     """Lookup the person for an given nickname
 | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-08-27 19:10:38 +00:00
										 |  |  |     if path.endswith('#/publicKey'): | 
					
						
							|  |  |  |         path = path.replace('#/publicKey', '') | 
					
						
							| 
									
										
										
										
											2022-08-27 19:15:58 +00:00
										 |  |  |     elif path.endswith('/main-key'): | 
					
						
							|  |  |  |         path = path.replace('/main-key', '') | 
					
						
							| 
									
										
										
										
											2022-08-27 19:10:38 +00:00
										 |  |  |     elif path.endswith('#main-key'): | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |         path = path.replace('#main-key', '') | 
					
						
							| 
									
										
										
										
											2019-08-05 15:52:18 +00:00
										 |  |  |     # is this a shared inbox lookup? | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     is_shared_inbox = False | 
					
						
							|  |  |  |     if path in ('/inbox', '/users/inbox', '/sharedInbox'): | 
					
						
							| 
									
										
										
										
											2019-08-23 13:47:29 +00:00
										 |  |  |         # shared inbox actor on @domain@domain | 
					
						
							| 
									
										
										
										
											2021-08-31 18:30:39 +00:00
										 |  |  |         path = '/users/inbox' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         is_shared_inbox = True | 
					
						
							| 
									
										
										
										
											2019-08-05 15:22:59 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         not_person_lookup = ('/inbox', '/outbox', '/outboxarchive', | 
					
						
							|  |  |  |                              '/followers', '/following', '/featured', | 
					
						
							|  |  |  |                              '.png', '.jpg', '.gif', '.svg', '.mpv') | 
					
						
							|  |  |  |         for ending in not_person_lookup: | 
					
						
							| 
									
										
										
										
											2019-08-05 15:22:59 +00:00
										 |  |  |             if path.endswith(ending): | 
					
						
							|  |  |  |                 return None | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     nickname = None | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     if path.startswith('/users/'): | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |         nickname = path.replace('/users/', '', 1) | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     if path.startswith('/@'): | 
					
						
							| 
									
										
										
										
											2023-04-23 15:55:48 +00:00
										 |  |  |         if '/@/' not in path: | 
					
						
							|  |  |  |             nickname = path.replace('/@', '', 1) | 
					
						
							| 
									
										
										
										
											2019-07-03 09:40:27 +00:00
										 |  |  |     if not nickname: | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not is_shared_inbox and not valid_nickname(domain, nickname): | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2021-12-26 18:17:37 +00:00
										 |  |  |     domain = remove_domain_port(domain) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |     filename = acct_handle_dir(base_dir, handle) + '.json' | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     if not os.path.isfile(filename): | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     person_json = load_json(filename) | 
					
						
							|  |  |  |     if not is_shared_inbox: | 
					
						
							| 
									
										
										
										
											2022-06-12 12:30:14 +00:00
										 |  |  |         person_upgrade_actor(base_dir, person_json, filename) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     # if not person_json: | 
					
						
							|  |  |  |     #     person_json={"user": "unknown"} | 
					
						
							|  |  |  |     return person_json | 
					
						
							| 
									
										
										
										
											2019-06-29 14:35:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 16:50:20 +00:00
										 |  |  | def person_box_json(recent_posts_cache: {}, | 
					
						
							| 
									
										
										
										
											2022-09-08 17:59:19 +00:00
										 |  |  |                     base_dir: str, domain: str, port: int, path: str, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     http_prefix: str, no_of_items: int, boxname: str, | 
					
						
							| 
									
										
										
										
											2021-12-28 16:50:20 +00:00
										 |  |  |                     authorized: bool, | 
					
						
							|  |  |  |                     newswire_votes_threshold: int, positive_voting: bool, | 
					
						
							|  |  |  |                     voting_time_mins: int) -> {}: | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |     """Obtain the inbox/outbox/moderation feed for the given person
 | 
					
						
							| 
									
										
										
										
											2019-06-29 14:35:26 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if boxname not in ('inbox', 'dm', 'tlreplies', 'tlmedia', 'tlblogs', | 
					
						
							|  |  |  |                        'tlnews', 'tlfeatures', 'outbox', 'moderation', | 
					
						
							|  |  |  |                        'tlbookmarks', 'bookmarks'): | 
					
						
							| 
									
										
										
										
											2021-12-28 16:50:20 +00:00
										 |  |  |         print('ERROR: person_box_json invalid box name ' + boxname) | 
					
						
							| 
									
										
										
										
											2019-07-04 16:24:23 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     if not '/' + boxname in path: | 
					
						
							| 
									
										
										
										
											2019-06-29 16:47:37 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-29 17:12:26 +00:00
										 |  |  |     # Only show the header by default | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     header_only = True | 
					
						
							| 
									
										
										
										
											2019-06-29 17:12:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-20 17:10:20 +00:00
										 |  |  |     # first post in the timeline | 
					
						
							|  |  |  |     first_post_id = '' | 
					
						
							|  |  |  |     if ';firstpost=' in path: | 
					
						
							|  |  |  |         first_post_id = \ | 
					
						
							|  |  |  |             path.split(';firstpost=')[1] | 
					
						
							| 
									
										
										
										
											2022-12-28 14:14:44 +00:00
										 |  |  |         if ';' in first_post_id: | 
					
						
							|  |  |  |             first_post_id = first_post_id.split(';')[0] | 
					
						
							| 
									
										
										
										
											2022-11-20 17:10:20 +00:00
										 |  |  |         first_post_id = \ | 
					
						
							|  |  |  |             first_post_id.replace('--', '/') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-29 16:47:37 +00:00
										 |  |  |     # handle page numbers | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     page_number = None | 
					
						
							| 
									
										
										
										
											2019-06-29 16:47:37 +00:00
										 |  |  |     if '?page=' in path: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         page_number = path.split('?page=')[1] | 
					
						
							| 
									
										
										
										
											2022-11-20 17:10:20 +00:00
										 |  |  |         if ';' in page_number: | 
					
						
							|  |  |  |             page_number = page_number.split(';')[0] | 
					
						
							| 
									
										
										
										
											2022-09-08 10:34:12 +00:00
										 |  |  |         if len(page_number) > 5: | 
					
						
							|  |  |  |             page_number = 1 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if page_number == 'true': | 
					
						
							|  |  |  |             page_number = 1 | 
					
						
							| 
									
										
										
										
											2019-06-29 16:47:37 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 page_number = int(page_number) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |             except BaseException: | 
					
						
							| 
									
										
										
										
											2021-12-28 16:50:20 +00:00
										 |  |  |                 print('EX: person_box_json unable to convert to int ' + | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                       str(page_number)) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |         path = path.split('?page=')[0] | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         header_only = False | 
					
						
							| 
									
										
										
										
											2019-06-29 16:47:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     if not path.endswith('/' + boxname): | 
					
						
							| 
									
										
										
										
											2019-06-29 15:18:35 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     nickname = None | 
					
						
							| 
									
										
										
										
											2019-06-29 14:35:26 +00:00
										 |  |  |     if path.startswith('/users/'): | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |         nickname = path.replace('/users/', '', 1).replace('/' + boxname, '') | 
					
						
							| 
									
										
										
										
											2019-06-29 14:35:26 +00:00
										 |  |  |     if path.startswith('/@'): | 
					
						
							| 
									
										
										
										
											2023-04-23 15:55:48 +00:00
										 |  |  |         if '/@/' not in path: | 
					
						
							|  |  |  |             nickname = path.replace('/@', '', 1).replace('/' + boxname, '') | 
					
						
							| 
									
										
										
										
											2019-07-03 09:40:27 +00:00
										 |  |  |     if not nickname: | 
					
						
							| 
									
										
										
										
											2019-06-29 15:18:35 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2021-12-28 14:41:10 +00:00
										 |  |  |     if not valid_nickname(domain, nickname): | 
					
						
							| 
									
										
										
										
											2019-06-29 15:18:35 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     if boxname == 'inbox': | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         return create_inbox(recent_posts_cache, | 
					
						
							| 
									
										
										
										
											2022-05-31 15:16:55 +00:00
										 |  |  |                             base_dir, nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                             http_prefix, | 
					
						
							| 
									
										
										
										
											2022-11-20 17:10:20 +00:00
										 |  |  |                             no_of_items, header_only, page_number, | 
					
						
							|  |  |  |                             first_post_id) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if boxname == 'dm': | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         return create_dm_timeline(recent_posts_cache, | 
					
						
							| 
									
										
										
										
											2022-05-31 15:16:55 +00:00
										 |  |  |                                   base_dir, nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                                   http_prefix, | 
					
						
							| 
									
										
										
										
											2022-11-20 18:09:30 +00:00
										 |  |  |                                   no_of_items, header_only, page_number, | 
					
						
							|  |  |  |                                   first_post_id) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if boxname in ('tlbookmarks', 'bookmarks'): | 
					
						
							| 
									
										
										
										
											2022-05-31 15:16:55 +00:00
										 |  |  |         return create_bookmarks_timeline(base_dir, nickname, domain, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                                          port, http_prefix, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                          no_of_items, header_only, | 
					
						
							|  |  |  |                                          page_number) | 
					
						
							|  |  |  |     if boxname == 'tlreplies': | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         return create_replies_timeline(recent_posts_cache, | 
					
						
							| 
									
										
										
										
											2022-05-31 15:16:55 +00:00
										 |  |  |                                        base_dir, nickname, domain, | 
					
						
							| 
									
										
										
										
											2021-12-25 17:09:22 +00:00
										 |  |  |                                        port, http_prefix, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                        no_of_items, header_only, | 
					
						
							| 
									
										
										
										
											2022-11-20 18:09:30 +00:00
										 |  |  |                                        page_number, | 
					
						
							|  |  |  |                                        first_post_id) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if boxname == 'tlmedia': | 
					
						
							| 
									
										
										
										
											2022-05-31 15:16:55 +00:00
										 |  |  |         return create_media_timeline(base_dir, nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                      http_prefix, no_of_items, header_only, | 
					
						
							|  |  |  |                                      page_number) | 
					
						
							|  |  |  |     if boxname == 'tlnews': | 
					
						
							| 
									
										
										
										
											2022-05-31 15:16:55 +00:00
										 |  |  |         return create_news_timeline(base_dir, domain, port, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                     http_prefix, no_of_items, header_only, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                                     newswire_votes_threshold, positive_voting, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                     voting_time_mins, page_number) | 
					
						
							|  |  |  |     if boxname == 'tlfeatures': | 
					
						
							| 
									
										
										
										
											2022-05-31 15:16:55 +00:00
										 |  |  |         return create_features_timeline(base_dir, nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                         http_prefix, no_of_items, header_only, | 
					
						
							|  |  |  |                                         page_number) | 
					
						
							|  |  |  |     if boxname == 'tlblogs': | 
					
						
							| 
									
										
										
										
											2022-05-31 15:16:55 +00:00
										 |  |  |         return create_blogs_timeline(base_dir, nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                      http_prefix, no_of_items, header_only, | 
					
						
							| 
									
										
										
										
											2023-01-02 10:44:49 +00:00
										 |  |  |                                      page_number) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if boxname == 'outbox': | 
					
						
							| 
									
										
										
										
											2022-05-31 15:16:55 +00:00
										 |  |  |         return create_outbox(base_dir, nickname, domain, port, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                              http_prefix, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                              no_of_items, header_only, authorized, | 
					
						
							|  |  |  |                              page_number) | 
					
						
							|  |  |  |     if boxname == 'moderation': | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         return create_moderation(base_dir, nickname, domain, port, | 
					
						
							|  |  |  |                                  http_prefix, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                                  no_of_items, header_only, | 
					
						
							|  |  |  |                                  page_number) | 
					
						
							| 
									
										
										
										
											2019-08-12 13:22:17 +00:00
										 |  |  |     return None | 
					
						
							| 
									
										
										
										
											2019-06-29 14:35:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def set_display_nickname(base_dir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |                          display_name: str) -> bool: | 
					
						
							| 
									
										
										
										
											2022-06-12 10:58:00 +00:00
										 |  |  |     """Sets the display name for an account
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |     if len(display_name) > 32: | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-09-15 09:16:03 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |     filename = acct_handle_dir(base_dir, handle) + '.json' | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     if not os.path.isfile(filename): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     person_json = load_json(filename) | 
					
						
							|  |  |  |     if not person_json: | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |     person_json['name'] = display_name | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     save_json(person_json, filename) | 
					
						
							| 
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 |  |  |     return True | 
					
						
							| 
									
										
										
										
											2019-06-28 20:00:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def set_bio(base_dir: str, nickname: str, domain: str, bio: str) -> bool: | 
					
						
							| 
									
										
										
										
											2021-12-19 18:18:55 +00:00
										 |  |  |     """Only used within tests
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     if len(bio) > 32: | 
					
						
							| 
									
										
										
										
											2019-06-28 20:00:25 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-09-15 09:16:03 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |     filename = acct_handle_dir(base_dir, handle) + '.json' | 
					
						
							| 
									
										
										
										
											2019-06-28 20:00:25 +00:00
										 |  |  |     if not os.path.isfile(filename): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     person_json = load_json(filename) | 
					
						
							|  |  |  |     if not person_json: | 
					
						
							| 
									
										
										
										
											2019-06-28 20:00:25 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not person_json.get('summary'): | 
					
						
							| 
									
										
										
										
											2019-06-28 20:00:25 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     person_json['summary'] = bio | 
					
						
							| 
									
										
										
										
											2019-09-30 22:39:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     save_json(person_json, filename) | 
					
						
							| 
									
										
										
										
											2019-06-28 20:00:25 +00:00
										 |  |  |     return True | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-08 11:01:22 +00:00
										 |  |  | def _unsuspend_media_for_account(base_dir: str, account_dir: str) -> None: | 
					
						
							|  |  |  |     """Unsuspends all media for an account
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     account_media_log_filename = account_dir + '/media_log.txt' | 
					
						
							|  |  |  |     if not os.path.isfile(account_media_log_filename): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     media_log = [] | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         with open(account_media_log_filename, 'r', | 
					
						
							|  |  |  |                   encoding='utf-8') as fp_log: | 
					
						
							|  |  |  |             media_log = fp_log.read().split('\n') | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         print('EX: suspend unable to read media log for ' + account_dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for filename in media_log: | 
					
						
							|  |  |  |         media_filename = base_dir + filename | 
					
						
							|  |  |  |         if not os.path.isfile(media_filename + '.suspended'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             os.rename(media_filename + '.suspended', media_filename) | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: unable to unsuspend media ' + media_filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def reenable_account(base_dir: str, nickname: str, domain: str) -> None: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |     """Removes an account suspension
 | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |     suspended_filename = data_dir(base_dir) + '/suspended.txt' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if os.path.isfile(suspended_filename): | 
					
						
							| 
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 |  |  |         lines: list[str] = [] | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(suspended_filename, 'r', encoding='utf-8') as fp_sus: | 
					
						
							|  |  |  |                 lines = fp_sus.readlines() | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: reenable_account unable to read ' + suspended_filename) | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |             with open(suspended_filename, 'w+', encoding='utf-8') as fp_sus: | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |                 for suspended in lines: | 
					
						
							|  |  |  |                     if suspended.strip('\n').strip('\r') != nickname: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                         fp_sus.write(suspended) | 
					
						
							| 
									
										
										
										
											2021-12-25 15:28:52 +00:00
										 |  |  |         except OSError as ex: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: reenable_account unable to save ' + | 
					
						
							|  |  |  |                   suspended_filename + ' ' + str(ex)) | 
					
						
							| 
									
										
										
										
											2025-04-08 11:01:22 +00:00
										 |  |  |         account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |         _unsuspend_media_for_account(base_dir, account_dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _suspend_media_for_account(base_dir: str, account_dir: str) -> None: | 
					
						
							|  |  |  |     """Suspends all media for an account
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     account_media_log_filename = account_dir + '/media_log.txt' | 
					
						
							|  |  |  |     if not os.path.isfile(account_media_log_filename): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     media_log = [] | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         with open(account_media_log_filename, 'r', | 
					
						
							|  |  |  |                   encoding='utf-8') as fp_log: | 
					
						
							|  |  |  |             media_log = fp_log.read().split('\n') | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         print('EX: suspend unable to read media log for ' + account_dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for filename in media_log: | 
					
						
							|  |  |  |         media_filename = base_dir + filename | 
					
						
							|  |  |  |         if not os.path.isfile(media_filename): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             os.rename(media_filename, media_filename + '.suspended') | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: unable to suspend media ' + media_filename) | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def suspend_account(base_dir: str, nickname: str, domain: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  |     """Suspends the given account
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     # Don't suspend the admin | 
					
						
							| 
									
										
										
										
											2021-12-31 21:18:12 +00:00
										 |  |  |     admin_nickname = get_config_param(base_dir, 'admin') | 
					
						
							|  |  |  |     if not admin_nickname: | 
					
						
							| 
									
										
										
										
											2020-10-10 16:10:32 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-31 21:18:12 +00:00
										 |  |  |     if nickname == admin_nickname: | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Don't suspend moderators | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |     moderators_file = data_dir(base_dir) + '/moderators.txt' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if os.path.isfile(moderators_file): | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(moderators_file, 'r', encoding='utf-8') as fp_mod: | 
					
						
							|  |  |  |                 lines = fp_mod.readlines() | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: suspend_account unable too read ' + moderators_file) | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  |         for moderator in lines: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |             if moderator.strip('\n').strip('\r') == nickname: | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  |                 return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-08 11:01:22 +00:00
										 |  |  |     account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |     salt_filename = account_dir + '/.salt' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if os.path.isfile(salt_filename): | 
					
						
							| 
									
										
										
										
											2021-09-05 10:17:43 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             os.remove(salt_filename) | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             print('EX: suspend_account unable to delete ' + salt_filename) | 
					
						
							|  |  |  |     token_filename = acct_dir(base_dir, nickname, domain) + '/.token' | 
					
						
							|  |  |  |     if os.path.isfile(token_filename): | 
					
						
							| 
									
										
										
										
											2021-09-05 10:17:43 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             os.remove(token_filename) | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: suspend_account unable to delete 2 ' + token_filename) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |     suspended_filename = data_dir(base_dir) + '/suspended.txt' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if os.path.isfile(suspended_filename): | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(suspended_filename, 'r', encoding='utf-8') as fp_sus: | 
					
						
							|  |  |  |                 lines = fp_sus.readlines() | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: suspend_account unable to read 2 ' + suspended_filename) | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  |         for suspended in lines: | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |             if suspended.strip('\n').strip('\r') == nickname: | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  |                 return | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |             with open(suspended_filename, 'a+', encoding='utf-8') as fp_sus: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 fp_sus.write(nickname + '\n') | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: suspend_account unable to append ' + suspended_filename) | 
					
						
							| 
									
										
										
										
											2019-08-13 09:24:55 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |             with open(suspended_filename, 'w+', encoding='utf-8') as fp_sus: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 fp_sus.write(nickname + '\n') | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: suspend_account unable to write ' + suspended_filename) | 
					
						
							| 
									
										
										
										
											2025-04-08 11:01:22 +00:00
										 |  |  |     _suspend_media_for_account(base_dir, account_dir) | 
					
						
							| 
									
										
										
										
											2019-08-13 11:59:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-12 12:30:14 +00:00
										 |  |  | def can_remove_post(base_dir: str, | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  |                     domain: str, port: int, post_id: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-13 15:03:34 +00:00
										 |  |  |     """Returns true if the given post can be removed
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2023-08-14 18:46:27 +00:00
										 |  |  |     if not contains_statuses(post_id): | 
					
						
							| 
									
										
										
										
											2019-08-13 15:03:34 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 |  |  |     domain_full = get_full_domain(domain, port) | 
					
						
							| 
									
										
										
										
											2019-08-13 15:03:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # is the post by the admin? | 
					
						
							| 
									
										
										
										
											2021-12-31 21:18:12 +00:00
										 |  |  |     admin_nickname = get_config_param(base_dir, 'admin') | 
					
						
							|  |  |  |     if not admin_nickname: | 
					
						
							| 
									
										
										
										
											2020-10-10 16:10:32 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-31 21:18:12 +00:00
										 |  |  |     if domain_full + '/users/' + admin_nickname + '/' in post_id: | 
					
						
							| 
									
										
										
										
											2019-08-13 15:03:34 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # is the post by a moderator? | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |     moderators_file = data_dir(base_dir) + '/moderators.txt' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if os.path.isfile(moderators_file): | 
					
						
							| 
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 |  |  |         lines: list[str] = [] | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(moderators_file, 'r', encoding='utf-8') as fp_mod: | 
					
						
							|  |  |  |                 lines = fp_mod.readlines() | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: can_remove_post unable to read ' + moderators_file) | 
					
						
							| 
									
										
										
										
											2019-08-13 15:03:34 +00:00
										 |  |  |         for moderator in lines: | 
					
						
							| 
									
										
										
										
											2021-12-26 19:47:06 +00:00
										 |  |  |             if domain_full + '/users/' + \ | 
					
						
							|  |  |  |                moderator.strip('\n') + '/' in post_id: | 
					
						
							| 
									
										
										
										
											2019-08-13 15:03:34 +00:00
										 |  |  |                 return False | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def _remove_tags_for_nickname(base_dir: str, nickname: str, | 
					
						
							|  |  |  |                               domain: str, port: int) -> None: | 
					
						
							| 
									
										
										
										
											2019-08-13 12:14:11 +00:00
										 |  |  |     """Removes tags for a nickname
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |     if not os.path.isdir(base_dir + '/tags'): | 
					
						
							| 
									
										
										
										
											2019-08-13 12:14:11 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 |  |  |     domain_full = get_full_domain(domain, port) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     match_str = domain_full + '/users/' + nickname + '/' | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |     directory = os.fsencode(base_dir + '/tags/') | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     for fname in os.scandir(directory): | 
					
						
							|  |  |  |         filename = os.fsdecode(fname.name) | 
					
						
							| 
									
										
										
										
											2019-08-13 12:14:11 +00:00
										 |  |  |         if not filename.endswith(".txt"): | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2020-09-12 09:50:24 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2023-05-25 08:52:19 +00:00
										 |  |  |             tag_filename = os.path.join(base_dir + '/tags/', filename) | 
					
						
							| 
									
										
										
										
											2022-08-22 20:19:20 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |             print('EX: _remove_tags_for_nickname unable to join ' + | 
					
						
							| 
									
										
										
										
											2023-05-25 08:52:19 +00:00
										 |  |  |                   base_dir + '/tags/ ' + str(filename)) | 
					
						
							| 
									
										
										
										
											2020-09-12 09:50:24 +00:00
										 |  |  |             continue | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if not os.path.isfile(tag_filename): | 
					
						
							| 
									
										
										
										
											2019-11-27 09:51:59 +00:00
										 |  |  |             continue | 
					
						
							| 
									
										
										
										
											2022-06-10 11:43:33 +00:00
										 |  |  |         if not text_in_file(match_str, tag_filename): | 
					
						
							| 
									
										
										
										
											2019-08-13 12:14:11 +00:00
										 |  |  |             continue | 
					
						
							| 
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 |  |  |         lines: list[str] = [] | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(tag_filename, 'r', encoding='utf-8') as fp_tag: | 
					
						
							|  |  |  |                 lines = fp_tag.readlines() | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: _remove_tags_for_nickname unable to read ' + | 
					
						
							|  |  |  |                   tag_filename) | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2024-07-14 13:01:46 +00:00
										 |  |  |             with open(tag_filename, 'w+', encoding='utf-8') as fp_tag: | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |                 for tagline in lines: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     if match_str not in tagline: | 
					
						
							| 
									
										
										
										
											2024-07-14 13:01:46 +00:00
										 |  |  |                         fp_tag.write(tagline) | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |             print('EX: _remove_tags_for_nickname unable to write ' + | 
					
						
							|  |  |  |                   tag_filename) | 
					
						
							| 
									
										
										
										
											2019-08-13 12:14:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-08 11:14:09 +00:00
										 |  |  | def _remove_account_media(base_dir: str, nickname: str, domain: str) -> None: | 
					
						
							|  |  |  |     """Removes media for an account
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |     account_media_log_filename = account_dir + '/media_log.txt' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     media_log = [] | 
					
						
							|  |  |  |     if os.path.isfile(account_media_log_filename): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             with open(account_media_log_filename, 'r', | 
					
						
							|  |  |  |                       encoding='utf-8') as fp_log: | 
					
						
							|  |  |  |                 media_log = fp_log.read().split('\n') | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: remove unable to read media log for ' + nickname) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for filename in media_log: | 
					
						
							|  |  |  |         media_filename = base_dir + filename | 
					
						
							|  |  |  |         if not os.path.isfile(media_filename): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             os.remove(media_filename) | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: unable to remove media ' + media_filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def remove_account(base_dir: str, nickname: str, | 
					
						
							|  |  |  |                    domain: str, port: int) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-13 11:59:38 +00:00
										 |  |  |     """Removes an account
 | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2019-08-13 12:00:17 +00:00
										 |  |  |     # Don't remove the admin | 
					
						
							| 
									
										
										
										
											2021-12-31 21:18:12 +00:00
										 |  |  |     admin_nickname = get_config_param(base_dir, 'admin') | 
					
						
							|  |  |  |     if not admin_nickname: | 
					
						
							| 
									
										
										
										
											2020-10-10 16:10:32 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-31 21:18:12 +00:00
										 |  |  |     if nickname == admin_nickname: | 
					
						
							| 
									
										
										
										
											2019-08-13 11:59:38 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 12:00:17 +00:00
										 |  |  |     # Don't remove moderators | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |     moderators_file = data_dir(base_dir) + '/moderators.txt' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if os.path.isfile(moderators_file): | 
					
						
							| 
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 |  |  |         lines: list[str] = [] | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(moderators_file, 'r', encoding='utf-8') as fp_mod: | 
					
						
							|  |  |  |                 lines = fp_mod.readlines() | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: remove_account unable to read ' + moderators_file) | 
					
						
							| 
									
										
										
										
											2019-08-13 11:59:38 +00:00
										 |  |  |         for moderator in lines: | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |             if moderator.strip('\n') == nickname: | 
					
						
							| 
									
										
										
										
											2019-08-13 11:59:38 +00:00
										 |  |  |                 return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-08 11:01:22 +00:00
										 |  |  |     reenable_account(base_dir, nickname, domain) | 
					
						
							| 
									
										
										
										
											2025-04-08 11:14:09 +00:00
										 |  |  |     _remove_account_media(base_dir, nickname, domain) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |     remove_password(base_dir, nickname) | 
					
						
							|  |  |  |     _remove_tags_for_nickname(base_dir, nickname, domain, port) | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |     if os.path.isdir(base_dir + '/deactivated/' + handle): | 
					
						
							|  |  |  |         shutil.rmtree(base_dir + '/deactivated/' + handle, | 
					
						
							| 
									
										
										
										
											2024-05-16 15:57:44 +00:00
										 |  |  |                       ignore_errors=False) | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |     handle_dir = acct_handle_dir(base_dir, handle) | 
					
						
							|  |  |  |     if os.path.isdir(handle_dir): | 
					
						
							| 
									
										
										
										
											2024-05-16 15:57:44 +00:00
										 |  |  |         shutil.rmtree(handle_dir, ignore_errors=False) | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |     if os.path.isfile(handle_dir + '.json'): | 
					
						
							| 
									
										
										
										
											2021-09-05 10:17:43 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |             os.remove(handle_dir + '.json') | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  |             print('EX: remove_account unable to delete ' + | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |                   handle_dir + '.json') | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |     if os.path.isfile(base_dir + '/wfendpoints/' + handle + '.json'): | 
					
						
							| 
									
										
										
										
											2021-09-05 10:17:43 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |             os.remove(base_dir + '/wfendpoints/' + handle + '.json') | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  |             print('EX: remove_account unable to delete ' + | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                   base_dir + '/wfendpoints/' + handle + '.json') | 
					
						
							|  |  |  |     if os.path.isfile(base_dir + '/keys/private/' + handle + '.key'): | 
					
						
							| 
									
										
										
										
											2021-09-05 10:17:43 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |             os.remove(base_dir + '/keys/private/' + handle + '.key') | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  |             print('EX: remove_account unable to delete ' + | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                   base_dir + '/keys/private/' + handle + '.key') | 
					
						
							|  |  |  |     if os.path.isfile(base_dir + '/keys/public/' + handle + '.pem'): | 
					
						
							| 
									
										
										
										
											2021-09-05 10:17:43 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |             os.remove(base_dir + '/keys/public/' + handle + '.pem') | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  |             print('EX: remove_account unable to delete ' + | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                   base_dir + '/keys/public/' + handle + '.pem') | 
					
						
							|  |  |  |     if os.path.isdir(base_dir + '/sharefiles/' + nickname): | 
					
						
							|  |  |  |         shutil.rmtree(base_dir + '/sharefiles/' + nickname, | 
					
						
							| 
									
										
										
										
											2024-05-16 15:57:44 +00:00
										 |  |  |                       ignore_errors=False) | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |     if os.path.isfile(base_dir + '/wfdeactivated/' + handle + '.json'): | 
					
						
							| 
									
										
										
										
											2021-09-05 10:17:43 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |             os.remove(base_dir + '/wfdeactivated/' + handle + '.json') | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  |             print('EX: remove_account unable to delete ' + | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                   base_dir + '/wfdeactivated/' + handle + '.json') | 
					
						
							|  |  |  |     if os.path.isdir(base_dir + '/sharefilesdeactivated/' + nickname): | 
					
						
							|  |  |  |         shutil.rmtree(base_dir + '/sharefilesdeactivated/' + nickname, | 
					
						
							| 
									
										
										
										
											2024-05-16 15:57:44 +00:00
										 |  |  |                       ignore_errors=False) | 
					
						
							| 
									
										
										
										
											2021-02-13 10:01:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 12:10:21 +00:00
										 |  |  |     refresh_newswire(base_dir) | 
					
						
							| 
									
										
										
										
											2021-02-13 10:01:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 11:59:38 +00:00
										 |  |  |     return True | 
					
						
							| 
									
										
										
										
											2019-11-05 10:26:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def deactivate_account(base_dir: str, nickname: str, domain: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-11-05 10:26:36 +00:00
										 |  |  |     """Makes an account temporarily unavailable
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2019-11-05 12:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |     account_dir = acct_handle_dir(base_dir, handle) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not os.path.isdir(account_dir): | 
					
						
							| 
									
										
										
										
											2019-11-05 10:37:37 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     deactivated_dir = base_dir + '/deactivated' | 
					
						
							|  |  |  |     if not os.path.isdir(deactivated_dir): | 
					
						
							|  |  |  |         os.mkdir(deactivated_dir) | 
					
						
							|  |  |  |     shutil.move(account_dir, deactivated_dir + '/' + handle) | 
					
						
							| 
									
										
										
										
											2019-11-05 12:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |     if os.path.isfile(base_dir + '/wfendpoints/' + handle + '.json'): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         deactivated_webfinger_dir = base_dir + '/wfdeactivated' | 
					
						
							|  |  |  |         if not os.path.isdir(deactivated_webfinger_dir): | 
					
						
							|  |  |  |             os.mkdir(deactivated_webfinger_dir) | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |         shutil.move(base_dir + '/wfendpoints/' + handle + '.json', | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     deactivated_webfinger_dir + '/' + handle + '.json') | 
					
						
							| 
									
										
										
										
											2019-11-05 12:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |     if os.path.isdir(base_dir + '/sharefiles/' + nickname): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         deactivated_sharefiles_dir = base_dir + '/sharefilesdeactivated' | 
					
						
							|  |  |  |         if not os.path.isdir(deactivated_sharefiles_dir): | 
					
						
							|  |  |  |             os.mkdir(deactivated_sharefiles_dir) | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |         shutil.move(base_dir + '/sharefiles/' + nickname, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     deactivated_sharefiles_dir + '/' + nickname) | 
					
						
							| 
									
										
										
										
											2021-02-13 10:01:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 12:10:21 +00:00
										 |  |  |     refresh_newswire(base_dir) | 
					
						
							| 
									
										
										
										
											2021-02-13 10:01:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     return os.path.isdir(deactivated_dir + '/' + nickname + '@' + domain) | 
					
						
							| 
									
										
										
										
											2019-11-05 10:26:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-03 14:43:51 +00:00
										 |  |  | def activate_account2(base_dir: str, nickname: str, domain: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-11-05 10:26:36 +00:00
										 |  |  |     """Makes a deactivated account available
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  |     handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2019-11-05 12:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     deactivated_dir = base_dir + '/deactivated' | 
					
						
							|  |  |  |     deactivated_account_dir = deactivated_dir + '/' + handle | 
					
						
							|  |  |  |     if os.path.isdir(deactivated_account_dir): | 
					
						
							| 
									
										
										
										
											2022-12-18 15:29:54 +00:00
										 |  |  |         account_dir = acct_handle_dir(base_dir, handle) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if not os.path.isdir(account_dir): | 
					
						
							|  |  |  |             shutil.move(deactivated_account_dir, account_dir) | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     deactivated_webfinger_dir = base_dir + '/wfdeactivated' | 
					
						
							|  |  |  |     if os.path.isfile(deactivated_webfinger_dir + '/' + handle + '.json'): | 
					
						
							|  |  |  |         shutil.move(deactivated_webfinger_dir + '/' + handle + '.json', | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                     base_dir + '/wfendpoints/' + handle + '.json') | 
					
						
							| 
									
										
										
										
											2019-11-05 12:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     deactivated_sharefiles_dir = base_dir + '/sharefilesdeactivated' | 
					
						
							|  |  |  |     if os.path.isdir(deactivated_sharefiles_dir + '/' + nickname): | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |         if not os.path.isdir(base_dir + '/sharefiles/' + nickname): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             shutil.move(deactivated_sharefiles_dir + '/' + nickname, | 
					
						
							| 
									
										
										
										
											2021-12-25 16:17:53 +00:00
										 |  |  |                         base_dir + '/sharefiles/' + nickname) | 
					
						
							| 
									
										
										
										
											2019-11-05 12:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 12:10:21 +00:00
										 |  |  |     refresh_newswire(base_dir) | 
					
						
							| 
									
										
										
										
											2021-02-13 10:01:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def is_person_snoozed(base_dir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                       snooze_actor: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |     """Returns true if the given actor is snoozed
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     snoozed_filename = acct_dir(base_dir, nickname, domain) + '/snoozed.txt' | 
					
						
							|  |  |  |     if not os.path.isfile(snoozed_filename): | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-06-10 11:43:33 +00:00
										 |  |  |     if not text_in_file(snooze_actor + ' ', snoozed_filename): | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |         return False | 
					
						
							|  |  |  |     # remove the snooze entry if it has timed out | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     replace_str = None | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         with open(snoozed_filename, 'r', encoding='utf-8') as fp_snoozed: | 
					
						
							|  |  |  |             for line in fp_snoozed: | 
					
						
							|  |  |  |                 # is this the entry for the actor? | 
					
						
							|  |  |  |                 if line.startswith(snooze_actor + ' '): | 
					
						
							|  |  |  |                     snoozed_time_str1 = line.split(' ')[1] | 
					
						
							|  |  |  |                     snoozed_time_str = remove_eol(snoozed_time_str1) | 
					
						
							|  |  |  |                     # is there a time appended? | 
					
						
							|  |  |  |                     if snoozed_time_str.isdigit(): | 
					
						
							|  |  |  |                         snoozed_time = int(snoozed_time_str) | 
					
						
							|  |  |  |                         curr_time = int(time.time()) | 
					
						
							|  |  |  |                         # has the snooze timed out? | 
					
						
							|  |  |  |                         if int(curr_time - snoozed_time) > 60 * 60 * 24: | 
					
						
							|  |  |  |                             replace_str = line | 
					
						
							|  |  |  |                     else: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                         replace_str = line | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |                     break | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         print('EX: is_person_snoozed unable to read ' + snoozed_filename) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if replace_str: | 
					
						
							| 
									
										
										
										
											2021-06-21 22:52:04 +00:00
										 |  |  |         content = None | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(snoozed_filename, 'r', encoding='utf-8') as fp_snoozed: | 
					
						
							|  |  |  |                 content = fp_snoozed.read().replace(replace_str, '') | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: is_person_snoozed unable to read 2 ' + snoozed_filename) | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |         if content: | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |             try: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |                 with open(snoozed_filename, 'w+', | 
					
						
							| 
									
										
										
										
											2024-07-16 12:20:58 +00:00
										 |  |  |                           encoding='utf-8') as fp_snooze: | 
					
						
							|  |  |  |                     fp_snooze.write(content) | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |             except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |                 print('EX: is_person_snoozed unable to write ' + | 
					
						
							|  |  |  |                       snoozed_filename) | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-10 13:01:39 +00:00
										 |  |  |     if text_in_file(snooze_actor + ' ', snoozed_filename): | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |         return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def person_snooze(base_dir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                   snooze_actor: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |     """Temporarily ignores the given actor
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |     if not os.path.isdir(account_dir): | 
					
						
							|  |  |  |         print('ERROR: unknown account ' + account_dir) | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     snoozed_filename = account_dir + '/snoozed.txt' | 
					
						
							|  |  |  |     if os.path.isfile(snoozed_filename): | 
					
						
							| 
									
										
										
										
											2022-06-10 13:01:39 +00:00
										 |  |  |         if text_in_file(snooze_actor + ' ', snoozed_filename): | 
					
						
							| 
									
										
										
										
											2019-11-06 11:57:43 +00:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2024-07-14 13:01:46 +00:00
										 |  |  |         with open(snoozed_filename, 'a+', encoding='utf-8') as fp_snoozed: | 
					
						
							|  |  |  |             fp_snoozed.write(snooze_actor + ' ' + | 
					
						
							|  |  |  |                              str(int(time.time())) + '\n') | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |     except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |         print('EX: person_snooze unable to append ' + snoozed_filename) | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 18:12:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def person_unsnooze(base_dir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     snooze_actor: str) -> None: | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |     """Undoes a temporarily ignore of the given actor
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     account_dir = acct_dir(base_dir, nickname, domain) | 
					
						
							|  |  |  |     if not os.path.isdir(account_dir): | 
					
						
							|  |  |  |         print('ERROR: unknown account ' + account_dir) | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     snoozed_filename = account_dir + '/snoozed.txt' | 
					
						
							|  |  |  |     if not os.path.isfile(snoozed_filename): | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2022-06-10 11:43:33 +00:00
										 |  |  |     if not text_in_file(snooze_actor + ' ', snoozed_filename): | 
					
						
							| 
									
										
										
										
											2019-11-06 11:39:41 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     replace_str = None | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         with open(snoozed_filename, 'r', encoding='utf-8') as fp_snoozed: | 
					
						
							|  |  |  |             for line in fp_snoozed: | 
					
						
							|  |  |  |                 if line.startswith(snooze_actor + ' '): | 
					
						
							|  |  |  |                     replace_str = line | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         print('EX: person_unsnooze unable to read ' + snoozed_filename) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if replace_str: | 
					
						
							| 
									
										
										
										
											2021-06-21 22:52:04 +00:00
										 |  |  |         content = None | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(snoozed_filename, 'r', encoding='utf-8') as fp_snoozed: | 
					
						
							|  |  |  |                 content = fp_snoozed.read().replace(replace_str, '') | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: person_unsnooze unable to read 2 ' + snoozed_filename) | 
					
						
							| 
									
										
										
										
											2023-07-14 10:05:33 +00:00
										 |  |  |         if content is not None: | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |             try: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |                 with open(snoozed_filename, 'w+', | 
					
						
							| 
									
										
										
										
											2024-07-16 12:20:58 +00:00
										 |  |  |                           encoding='utf-8') as fp_snooze: | 
					
						
							|  |  |  |                     fp_snooze.write(content) | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |             except OSError: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 print('EX: unable to write ' + snoozed_filename) | 
					
						
							| 
									
										
										
										
											2020-08-05 21:12:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def set_person_notes(base_dir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                      handle: str, notes: str) -> bool: | 
					
						
							| 
									
										
										
										
											2020-08-05 21:12:09 +00:00
										 |  |  |     """Adds notes about a person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if '@' not in handle: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if handle.startswith('@'): | 
					
						
							|  |  |  |         handle = handle[1:] | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     notes_dir = acct_dir(base_dir, nickname, domain) + '/notes' | 
					
						
							|  |  |  |     if not os.path.isdir(notes_dir): | 
					
						
							|  |  |  |         os.mkdir(notes_dir) | 
					
						
							|  |  |  |     notes_filename = notes_dir + '/' + handle + '.txt' | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2024-07-14 13:01:46 +00:00
										 |  |  |         with open(notes_filename, 'w+', encoding='utf-8') as fp_notes: | 
					
						
							|  |  |  |             fp_notes.write(notes) | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |     except OSError: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         print('EX: unable to write ' + notes_filename) | 
					
						
							| 
									
										
										
										
											2021-11-25 21:18:53 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-08-05 21:12:09 +00:00
										 |  |  |     return True | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-20 18:22:28 +00:00
										 |  |  | def get_person_notes(base_dir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                      handle: str) -> str: | 
					
						
							|  |  |  |     """Returns notes about a person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     person_notes = '' | 
					
						
							|  |  |  |     person_notes_filename = \ | 
					
						
							|  |  |  |         acct_dir(base_dir, nickname, domain) + \ | 
					
						
							|  |  |  |         '/notes/' + handle + '.txt' | 
					
						
							|  |  |  |     if os.path.isfile(person_notes_filename): | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(person_notes_filename, 'r', | 
					
						
							|  |  |  |                       encoding='utf-8') as fp_notes: | 
					
						
							|  |  |  |                 person_notes = fp_notes.read() | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: get_person_notes unable to read ' + | 
					
						
							|  |  |  |                   person_notes_filename) | 
					
						
							| 
									
										
										
										
											2023-12-20 18:22:28 +00:00
										 |  |  |     return person_notes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-11 17:15:24 +00:00
										 |  |  | def get_person_notes_endpoint(base_dir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                               handle: str, | 
					
						
							|  |  |  |                               http_prefix: str, domain_full: str) -> {}: | 
					
						
							|  |  |  |     """Returns a json endpoint for account notes, for use by c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     actor = local_actor_url(http_prefix, nickname, domain_full) | 
					
						
							|  |  |  |     notes_json = { | 
					
						
							|  |  |  |         "@context": "http://www.w3.org/ns/anno.jsonld", | 
					
						
							|  |  |  |         "id": actor + "/private_account_notes", | 
					
						
							|  |  |  |         "type": "AnnotationCollection", | 
					
						
							|  |  |  |         "items": [] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     dir_str = acct_dir(base_dir, nickname, domain) + '/notes' | 
					
						
							|  |  |  |     if not os.path.isdir(dir_str): | 
					
						
							|  |  |  |         return notes_json | 
					
						
							|  |  |  |     handle_txt = '' | 
					
						
							|  |  |  |     if handle: | 
					
						
							|  |  |  |         handle_txt = handle + '.txt' | 
					
						
							|  |  |  |     for _, _, files in os.walk(dir_str): | 
					
						
							|  |  |  |         for filename in files: | 
					
						
							|  |  |  |             if not filename.endswith('.txt'): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if handle: | 
					
						
							|  |  |  |                 if filename != handle_txt: | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |             handle2 = filename.replace('.txt', '') | 
					
						
							|  |  |  |             notes_text = get_person_notes(base_dir, nickname, domain, handle2) | 
					
						
							|  |  |  |             if not notes_text: | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2024-10-11 17:21:38 +00:00
										 |  |  |             notes_json['items'].append({ | 
					
						
							| 
									
										
										
										
											2024-10-11 17:15:24 +00:00
										 |  |  |                 "id": actor + "/private_account_notes/" + handle2, | 
					
						
							|  |  |  |                 "type": "Annotation", | 
					
						
							|  |  |  |                 "bodyValue": notes_text, | 
					
						
							|  |  |  |                 "target": handle2 | 
					
						
							| 
									
										
										
										
											2024-10-11 17:21:38 +00:00
										 |  |  |             }) | 
					
						
							| 
									
										
										
										
											2024-10-11 17:15:24 +00:00
										 |  |  |         break | 
					
						
							|  |  |  |     return notes_json | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def _detect_users_path(url: str) -> str: | 
					
						
							| 
									
										
										
										
											2021-07-28 12:37:26 +00:00
										 |  |  |     """Tries to detect the /users/ path
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if '/' not in url: | 
					
						
							|  |  |  |         return '/users/' | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     users_paths = get_user_paths() | 
					
						
							|  |  |  |     for possible_users_path in users_paths: | 
					
						
							|  |  |  |         if possible_users_path in url: | 
					
						
							|  |  |  |             return possible_users_path | 
					
						
							| 
									
										
										
										
											2021-07-28 12:37:26 +00:00
										 |  |  |     return '/users/' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-11 14:38:47 +00:00
										 |  |  | def get_actor_json(host_domain: str, handle: str, http: bool, gnunet: bool, | 
					
						
							| 
									
										
										
										
											2022-04-29 13:54:13 +00:00
										 |  |  |                    ipfs: bool, ipns: bool, | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                    debug: bool, quiet: bool, | 
					
						
							|  |  |  |                    signing_priv_key_pem: str, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                    existing_session, mitm_servers: []) -> ({}, {}): | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |     """Returns the actor json
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-03-17 20:18:00 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         print('get_actor_json for ' + handle) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     original_actor = handle | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |     group_account = False | 
					
						
							| 
									
										
										
										
											2021-07-28 12:37:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # try to determine the users path | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     detected_users_path = _detect_users_path(handle) | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |     if '/@' in handle or \ | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |        detected_users_path in handle or \ | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |        handle.startswith('http') or \ | 
					
						
							| 
									
										
										
										
											2022-04-29 13:54:13 +00:00
										 |  |  |        handle.startswith('ipfs') or \ | 
					
						
							|  |  |  |        handle.startswith('ipns') or \ | 
					
						
							| 
									
										
										
										
											2021-07-01 17:59:24 +00:00
										 |  |  |        handle.startswith('hyper'): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         group_paths = get_group_paths() | 
					
						
							|  |  |  |         if detected_users_path in group_paths: | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |             group_account = True | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |         # format: https://domain/@nick | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         original_handle = handle | 
					
						
							|  |  |  |         if not has_users_path(original_handle): | 
					
						
							| 
									
										
										
										
											2021-03-17 20:18:00 +00:00
										 |  |  |             if not quiet or debug: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                 print('get_actor_json: Expected actor format: ' + | 
					
						
							| 
									
										
										
										
											2021-07-28 12:37:26 +00:00
										 |  |  |                       'https://domain/@nick or https://domain' + | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                       detected_users_path + 'nick') | 
					
						
							| 
									
										
										
										
											2021-06-03 19:46:35 +00:00
										 |  |  |             return None, None | 
					
						
							| 
									
										
										
										
											2021-12-27 17:20:01 +00:00
										 |  |  |         prefixes = get_protocol_prefixes() | 
					
						
							| 
									
										
										
										
											2021-06-03 18:30:48 +00:00
										 |  |  |         for prefix in prefixes: | 
					
						
							|  |  |  |             handle = handle.replace(prefix, '') | 
					
						
							| 
									
										
										
										
											2023-04-23 15:55:48 +00:00
										 |  |  |         if '/@/' not in handle: | 
					
						
							|  |  |  |             handle = handle.replace('/@', detected_users_path) | 
					
						
							| 
									
										
										
										
											2021-12-26 12:24:40 +00:00
										 |  |  |         paths = get_user_paths() | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         user_path_found = False | 
					
						
							|  |  |  |         for user_path in paths: | 
					
						
							|  |  |  |             if user_path in handle: | 
					
						
							|  |  |  |                 nickname = handle.split(user_path)[1] | 
					
						
							| 
									
										
										
										
											2022-06-21 11:58:50 +00:00
										 |  |  |                 nickname = remove_eol(nickname) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 domain = handle.split(user_path)[0] | 
					
						
							|  |  |  |                 user_path_found = True | 
					
						
							| 
									
										
										
										
											2021-07-04 11:39:13 +00:00
										 |  |  |                 break | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if not user_path_found and '://' in original_handle: | 
					
						
							|  |  |  |             domain = original_handle.split('://')[1] | 
					
						
							| 
									
										
										
										
											2021-06-03 18:30:48 +00:00
										 |  |  |             if '/' in domain: | 
					
						
							|  |  |  |                 domain = domain.split('/')[0] | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             if '://' + domain + '/' not in original_handle: | 
					
						
							| 
									
										
										
										
											2021-06-03 19:46:35 +00:00
										 |  |  |                 return None, None | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             nickname = original_handle.split('://' + domain + '/')[1] | 
					
						
							| 
									
										
										
										
											2021-06-03 18:30:48 +00:00
										 |  |  |             if '/' in nickname or '.' in nickname: | 
					
						
							| 
									
										
										
										
											2021-06-03 19:46:35 +00:00
										 |  |  |                 return None, None | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         # format: @nick@domain | 
					
						
							|  |  |  |         if '@' not in handle: | 
					
						
							|  |  |  |             if not quiet: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                 print('get_actor_json Syntax: --actor nickname@domain') | 
					
						
							| 
									
										
										
										
											2021-06-03 19:46:35 +00:00
										 |  |  |             return None, None | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |         if handle.startswith('@'): | 
					
						
							|  |  |  |             handle = handle[1:] | 
					
						
							| 
									
										
										
										
											2021-07-29 11:25:01 +00:00
										 |  |  |         elif handle.startswith('!'): | 
					
						
							|  |  |  |             # handle for a group | 
					
						
							|  |  |  |             handle = handle[1:] | 
					
						
							| 
									
										
										
										
											2021-12-26 00:07:44 +00:00
										 |  |  |             group_account = True | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |         if '@' not in handle: | 
					
						
							|  |  |  |             if not quiet: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                 print('get_actor_jsonSyntax: --actor nickname@domain') | 
					
						
							| 
									
										
										
										
											2021-06-03 19:46:35 +00:00
										 |  |  |             return None, None | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |         nickname = handle.split('@')[0] | 
					
						
							|  |  |  |         domain = handle.split('@')[1] | 
					
						
							| 
									
										
										
										
											2022-06-21 11:58:50 +00:00
										 |  |  |         domain = remove_eol(domain) | 
					
						
							| 
									
										
										
										
											2021-07-04 19:59:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-25 22:28:18 +00:00
										 |  |  |     cached_webfingers = {} | 
					
						
							| 
									
										
										
										
											2021-12-25 21:09:22 +00:00
										 |  |  |     proxy_type = None | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |     if http or domain.endswith('.onion'): | 
					
						
							| 
									
										
										
										
											2021-12-25 17:09:22 +00:00
										 |  |  |         http_prefix = 'http' | 
					
						
							| 
									
										
										
										
											2021-12-25 21:09:22 +00:00
										 |  |  |         proxy_type = 'tor' | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |     elif domain.endswith('.i2p'): | 
					
						
							| 
									
										
										
										
											2021-12-25 17:09:22 +00:00
										 |  |  |         http_prefix = 'http' | 
					
						
							| 
									
										
										
										
											2021-12-25 21:09:22 +00:00
										 |  |  |         proxy_type = 'i2p' | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |     elif gnunet: | 
					
						
							| 
									
										
										
										
											2021-12-25 17:09:22 +00:00
										 |  |  |         http_prefix = 'gnunet' | 
					
						
							| 
									
										
										
										
											2021-12-25 21:09:22 +00:00
										 |  |  |         proxy_type = 'gnunet' | 
					
						
							| 
									
										
										
										
											2022-04-29 13:54:13 +00:00
										 |  |  |     elif ipfs: | 
					
						
							|  |  |  |         http_prefix = 'ipfs' | 
					
						
							|  |  |  |         proxy_type = 'ipfs' | 
					
						
							|  |  |  |     elif ipns: | 
					
						
							|  |  |  |         http_prefix = 'ipns' | 
					
						
							|  |  |  |         proxy_type = 'ipfs' | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2021-03-17 20:18:00 +00:00
										 |  |  |         if '127.0.' not in domain and '192.168.' not in domain: | 
					
						
							| 
									
										
										
										
											2021-12-25 17:09:22 +00:00
										 |  |  |             http_prefix = 'https' | 
					
						
							| 
									
										
										
										
											2021-03-17 20:18:00 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2021-12-25 17:09:22 +00:00
										 |  |  |             http_prefix = 'http' | 
					
						
							| 
									
										
										
										
											2022-03-11 14:38:47 +00:00
										 |  |  |     if existing_session: | 
					
						
							|  |  |  |         session = existing_session | 
					
						
							| 
									
										
										
										
											2022-03-11 18:07:17 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: get_actor_json using existing session ' + | 
					
						
							|  |  |  |                   str(proxy_type) + ' ' + domain) | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2021-12-28 16:56:57 +00:00
										 |  |  |         session = create_session(proxy_type) | 
					
						
							| 
									
										
										
										
											2022-03-11 18:07:17 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: get_actor_json using session ' + | 
					
						
							|  |  |  |                   str(proxy_type) + ' ' + domain) | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |     if nickname == 'inbox': | 
					
						
							|  |  |  |         nickname = domain | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     person_url = None | 
					
						
							| 
									
										
										
										
											2022-01-02 14:51:02 +00:00
										 |  |  |     wf_request = None | 
					
						
							| 
									
										
										
										
											2021-09-12 19:53:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-26 17:07:14 +00:00
										 |  |  |     original_actor_lower = original_actor.lower() | 
					
						
							|  |  |  |     ends_with_instance_actor = False | 
					
						
							|  |  |  |     if original_actor_lower.endswith('/actor') or \ | 
					
						
							|  |  |  |        original_actor_lower.endswith('/instance.actor'): | 
					
						
							|  |  |  |         ends_with_instance_actor = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if '://' in original_actor and ends_with_instance_actor: | 
					
						
							| 
									
										
										
										
											2021-09-02 13:02:07 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             print(original_actor + ' is an instance actor') | 
					
						
							|  |  |  |         person_url = original_actor | 
					
						
							|  |  |  |     elif '://' in original_actor and group_account: | 
					
						
							| 
									
										
										
										
											2021-09-12 19:48:05 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             print(original_actor + ' is a group actor') | 
					
						
							|  |  |  |         person_url = original_actor | 
					
						
							| 
									
										
										
										
											2021-09-02 13:02:07 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         handle = nickname + '@' + domain | 
					
						
							| 
									
										
										
										
											2023-10-12 12:59:04 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('get_actor_json webfinger: ' + handle) | 
					
						
							| 
									
										
										
										
											2022-01-02 14:51:02 +00:00
										 |  |  |         wf_request = webfinger_handle(session, handle, | 
					
						
							|  |  |  |                                       http_prefix, cached_webfingers, | 
					
						
							| 
									
										
										
										
											2022-03-11 14:38:47 +00:00
										 |  |  |                                       host_domain, __version__, debug, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                                       group_account, signing_priv_key_pem, | 
					
						
							|  |  |  |                                       mitm_servers) | 
					
						
							| 
									
										
										
										
											2022-01-02 14:51:02 +00:00
										 |  |  |         if not wf_request: | 
					
						
							| 
									
										
										
										
											2021-09-02 13:02:07 +00:00
										 |  |  |             if not quiet: | 
					
						
							| 
									
										
										
										
											2022-03-11 14:38:47 +00:00
										 |  |  |                 print('get_actor_json Unable to webfinger ' + handle + | 
					
						
							|  |  |  |                       ' ' + http_prefix + ' proxy: ' + str(proxy_type)) | 
					
						
							| 
									
										
										
										
											2021-07-30 13:00:23 +00:00
										 |  |  |             return None, None | 
					
						
							| 
									
										
										
										
											2022-01-02 14:51:02 +00:00
										 |  |  |         if not isinstance(wf_request, dict): | 
					
						
							| 
									
										
										
										
											2021-09-02 13:02:07 +00:00
										 |  |  |             if not quiet: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |                 print('get_actor_json Webfinger for ' + handle + | 
					
						
							| 
									
										
										
										
											2022-01-02 14:51:02 +00:00
										 |  |  |                       ' did not return a dict. ' + str(wf_request)) | 
					
						
							| 
									
										
										
										
											2021-09-02 13:02:07 +00:00
										 |  |  |             return None, None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not quiet: | 
					
						
							| 
									
										
										
										
											2022-01-02 14:51:02 +00:00
										 |  |  |             pprint(wf_request) | 
					
						
							| 
									
										
										
										
											2021-09-02 13:02:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-02 14:51:02 +00:00
										 |  |  |         if wf_request.get('errors'): | 
					
						
							| 
									
										
										
										
											2021-09-02 13:02:07 +00:00
										 |  |  |             if not quiet or debug: | 
					
						
							| 
									
										
										
										
											2022-01-02 14:51:02 +00:00
										 |  |  |                 print('get_actor_json wf_request error: ' + | 
					
						
							|  |  |  |                       str(wf_request['errors'])) | 
					
						
							| 
									
										
										
										
											2021-12-26 12:19:00 +00:00
										 |  |  |             if has_users_path(handle): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 person_url = original_actor | 
					
						
							| 
									
										
										
										
											2021-09-02 13:02:07 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 if debug: | 
					
						
							|  |  |  |                     print('No users path in ' + handle) | 
					
						
							|  |  |  |                 return None, None | 
					
						
							| 
									
										
										
										
											2021-07-29 11:25:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     profile_str = 'https://www.w3.org/ns/activitystreams' | 
					
						
							|  |  |  |     headers_list = ( | 
					
						
							| 
									
										
										
										
											2021-06-02 19:38:12 +00:00
										 |  |  |         "activity+json", "ld+json", "jrd+json" | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not person_url and wf_request: | 
					
						
							|  |  |  |         person_url = get_user_url(wf_request, 0, debug) | 
					
						
							| 
									
										
										
										
											2023-10-12 12:59:04 +00:00
										 |  |  |     if debug and person_url: | 
					
						
							|  |  |  |         print('\nget_actor_json getting json for ' + person_url) | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |     if nickname == domain: | 
					
						
							| 
									
										
										
										
											2021-12-26 12:24:40 +00:00
										 |  |  |         paths = get_user_paths() | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         for user_path in paths: | 
					
						
							| 
									
										
										
										
											2023-10-12 12:59:04 +00:00
										 |  |  |             if user_path != '/@': | 
					
						
							|  |  |  |                 person_url = person_url.replace(user_path, '/actor/') | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not person_url and group_account: | 
					
						
							|  |  |  |         person_url = http_prefix + '://' + domain + '/c/' + nickname | 
					
						
							|  |  |  |     if not person_url: | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |         # try single user instance | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         person_url = http_prefix + '://' + domain + '/' + nickname | 
					
						
							|  |  |  |         headers_list = ( | 
					
						
							| 
									
										
										
										
											2021-06-02 19:38:12 +00:00
										 |  |  |             "ld+json", "jrd+json", "activity+json" | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-09-12 19:48:05 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             print('Trying single user instance ' + person_url) | 
					
						
							|  |  |  |     if '/channel/' in person_url or '/accounts/' in person_url: | 
					
						
							|  |  |  |         headers_list = ( | 
					
						
							| 
									
										
										
										
											2021-06-02 19:38:12 +00:00
										 |  |  |             "ld+json", "jrd+json", "activity+json" | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-06-03 18:49:09 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         print('person_url: ' + person_url) | 
					
						
							|  |  |  |     for header_type in headers_list: | 
					
						
							|  |  |  |         header_mime_type = 'application/' + header_type | 
					
						
							|  |  |  |         as_header = { | 
					
						
							|  |  |  |             'Accept': header_mime_type + '; profile="' + profile_str + '"' | 
					
						
							| 
									
										
										
										
											2021-03-11 18:15:04 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         person_json = \ | 
					
						
							|  |  |  |             get_json(signing_priv_key_pem, session, person_url, as_header, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                      None, debug, mitm_servers, __version__, http_prefix, | 
					
						
							|  |  |  |                      host_domain, 20, quiet) | 
					
						
							| 
									
										
										
										
											2023-08-13 09:58:02 +00:00
										 |  |  |         if get_json_valid(person_json): | 
					
						
							| 
									
										
										
										
											2021-06-02 19:38:12 +00:00
										 |  |  |             if not quiet: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 pprint(person_json) | 
					
						
							|  |  |  |             return person_json, as_header | 
					
						
							| 
									
										
										
										
											2021-06-03 19:46:35 +00:00
										 |  |  |     return None, None | 
					
						
							| 
									
										
										
										
											2021-06-25 14:33:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-12 12:30:14 +00:00
										 |  |  | def get_person_avatar_url(base_dir: str, person_url: str, | 
					
						
							|  |  |  |                           person_cache: {}) -> str: | 
					
						
							| 
									
										
										
										
											2021-06-25 14:33:16 +00:00
										 |  |  |     """Returns the avatar url for the person
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     person_json = \ | 
					
						
							| 
									
										
										
										
											2022-06-09 16:54:44 +00:00
										 |  |  |         get_person_from_cache(base_dir, person_url, person_cache) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not person_json: | 
					
						
							| 
									
										
										
										
											2021-06-25 14:33:16 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # get from locally stored image | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if not person_json.get('id'): | 
					
						
							| 
									
										
										
										
											2021-06-25 14:33:16 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     actor_str = person_json['id'].replace('/', '-') | 
					
						
							|  |  |  |     avatar_image_path = base_dir + '/cache/avatars/' + actor_str | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     image_extension = get_image_extensions() | 
					
						
							|  |  |  |     for ext in image_extension: | 
					
						
							|  |  |  |         im_filename = avatar_image_path + '.' + ext | 
					
						
							|  |  |  |         im_path = '/avatars/' + actor_str + '.' + ext | 
					
						
							|  |  |  |         if not os.path.isfile(im_filename): | 
					
						
							|  |  |  |             im_filename = avatar_image_path.lower() + '.' + ext | 
					
						
							|  |  |  |             im_path = '/avatars/' + actor_str.lower() + '.' + ext | 
					
						
							|  |  |  |             if not os.path.isfile(im_filename): | 
					
						
							| 
									
										
										
										
											2021-09-13 19:38:15 +00:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2021-09-13 19:39:43 +00:00
										 |  |  |         if ext != 'svg': | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             return im_path | 
					
						
							|  |  |  |         content = '' | 
					
						
							| 
									
										
										
										
											2024-07-13 14:38:11 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             with open(im_filename, 'r', encoding='utf-8') as fp_im: | 
					
						
							|  |  |  |                 content = fp_im.read() | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: get_person_avatar_url unable to read ' + im_filename) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if not dangerous_svg(content, False): | 
					
						
							|  |  |  |             return im_path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if person_json.get('icon'): | 
					
						
							| 
									
										
										
										
											2025-02-04 10:32:19 +00:00
										 |  |  |         person_icon_url = get_person_icon(person_json) | 
					
						
							|  |  |  |         if person_icon_url: | 
					
						
							|  |  |  |             return person_icon_url | 
					
						
							| 
									
										
										
										
											2021-06-25 14:33:16 +00:00
										 |  |  |     return None | 
					
						
							| 
									
										
										
										
											2021-10-29 12:52:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 18:13:52 +00:00
										 |  |  | def add_actor_update_timestamp(actor_json: {}) -> None: | 
					
						
							| 
									
										
										
										
											2021-10-29 12:52:23 +00:00
										 |  |  |     """Adds 'updated' fields with a timestamp
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2023-11-20 22:27:58 +00:00
										 |  |  |     updated_time = date_utcnow() | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     curr_date_str = updated_time.strftime("%Y-%m-%dT%H:%M:%SZ") | 
					
						
							|  |  |  |     actor_json['updated'] = curr_date_str | 
					
						
							| 
									
										
										
										
											2021-10-29 12:52:23 +00:00
										 |  |  |     # add updated timestamp to avatar and banner | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     actor_json['icon']['updated'] = curr_date_str | 
					
						
							|  |  |  |     actor_json['image']['updated'] = curr_date_str | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def valid_sending_actor(session, base_dir: str, | 
					
						
							|  |  |  |                         nickname: str, domain: str, | 
					
						
							|  |  |  |                         person_cache: {}, | 
					
						
							|  |  |  |                         post_json_object: {}, | 
					
						
							|  |  |  |                         signing_priv_key_pem: str, | 
					
						
							| 
									
										
										
										
											2022-09-25 17:26:11 +00:00
										 |  |  |                         debug: bool, unit_test: bool, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                         system_language: str, | 
					
						
							|  |  |  |                         mitm_servers: []) -> bool: | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |     """When a post arrives in the inbox this is used to check that
 | 
					
						
							|  |  |  |     the sending actor is valid | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     # who sent this post? | 
					
						
							| 
									
										
										
										
											2024-01-09 16:59:23 +00:00
										 |  |  |     sending_actor = get_actor_from_post(post_json_object) | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-26 10:49:41 +00:00
										 |  |  |     if not isinstance(sending_actor, str): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if contains_invalid_actor_url_chars(sending_actor): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-14 15:25:57 +00:00
										 |  |  |     # If you are following them then allow their posts | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if is_following_actor(base_dir, nickname, domain, sending_actor): | 
					
						
							| 
									
										
										
										
											2021-12-14 15:25:57 +00:00
										 |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |     # sending to yourself (reminder) | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |     if sending_actor.endswith(domain + '/users/' + nickname): | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-13 12:40:09 +00:00
										 |  |  |     # download the actor | 
					
						
							|  |  |  |     # NOTE: the actor should not be obtained from the local cache, | 
					
						
							|  |  |  |     # because they may have changed fields which are being tested here, | 
					
						
							|  |  |  |     # such as the bio length | 
					
						
							| 
									
										
										
										
											2022-04-29 13:54:13 +00:00
										 |  |  |     gnunet = False | 
					
						
							|  |  |  |     ipfs = False | 
					
						
							|  |  |  |     ipns = False | 
					
						
							| 
									
										
										
										
											2022-03-13 12:40:09 +00:00
										 |  |  |     actor_json, _ = get_actor_json(domain, sending_actor, | 
					
						
							| 
									
										
										
										
											2022-04-29 13:54:13 +00:00
										 |  |  |                                    True, gnunet, ipfs, ipns, | 
					
						
							|  |  |  |                                    debug, True, | 
					
						
							| 
									
										
										
										
											2024-12-17 13:50:48 +00:00
										 |  |  |                                    signing_priv_key_pem, session, | 
					
						
							|  |  |  |                                    mitm_servers) | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |     if not actor_json: | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |         # if the actor couldn't be obtained then proceed anyway | 
					
						
							|  |  |  |         return True | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |     if not actor_json.get('preferredUsername'): | 
					
						
							|  |  |  |         print('REJECT: no preferredUsername within actor ' + str(actor_json)) | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-09-07 18:55:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-26 10:49:41 +00:00
										 |  |  |     # is this a known spam actor? | 
					
						
							| 
									
										
										
										
											2022-09-07 18:55:48 +00:00
										 |  |  |     actor_spam_filter_filename = \ | 
					
						
							|  |  |  |         acct_dir(base_dir, nickname, domain) + '/.reject_spam_actors' | 
					
						
							|  |  |  |     if not os.path.isfile(actor_spam_filter_filename): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |     # does the actor have a bio ? | 
					
						
							| 
									
										
										
										
											2021-12-25 21:32:15 +00:00
										 |  |  |     if not unit_test: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         bio_str = '' | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |         if actor_json.get('summary'): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             bio_str = remove_html(actor_json['summary']).strip() | 
					
						
							|  |  |  |         if not bio_str: | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |             # allow no bio if it's an actor in this instance | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             if domain not in sending_actor: | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                 # probably a spam actor with no bio | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 print('REJECT: spam actor ' + sending_actor) | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                 return False | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         if len(bio_str) < 10: | 
					
						
							| 
									
										
										
										
											2021-12-19 18:29:43 +00:00
										 |  |  |             print('REJECT: actor bio is not long enough ' + | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                   sending_actor + ' ' + bio_str) | 
					
						
							| 
									
										
										
										
											2021-12-19 18:29:43 +00:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         bio_str += ' ' + remove_html(actor_json['preferredUsername']) | 
					
						
							| 
									
										
										
										
											2021-12-14 14:35:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |         if actor_json.get('attachment'): | 
					
						
							|  |  |  |             if isinstance(actor_json['attachment'], list): | 
					
						
							|  |  |  |                 for tag in actor_json['attachment']: | 
					
						
							| 
									
										
										
										
											2021-12-14 14:35:51 +00:00
										 |  |  |                     if not isinstance(tag, dict): | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     if not tag.get('name'): | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     if isinstance(tag['name'], str): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                         bio_str += ' ' + tag['name'] | 
					
						
							| 
									
										
										
										
											2022-05-11 17:39:23 +00:00
										 |  |  |                     prop_value_name, _ = \ | 
					
						
							|  |  |  |                         get_attachment_property_value(tag) | 
					
						
							|  |  |  |                     if not prop_value_name: | 
					
						
							| 
									
										
										
										
											2021-12-14 14:35:51 +00:00
										 |  |  |                         continue | 
					
						
							| 
									
										
										
										
											2022-05-11 17:39:23 +00:00
										 |  |  |                     if tag.get(prop_value_name): | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     if isinstance(tag[prop_value_name], str): | 
					
						
							|  |  |  |                         bio_str += ' ' + tag[prop_value_name] | 
					
						
							| 
									
										
										
										
											2021-12-14 14:35:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |         if actor_json.get('name'): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             bio_str += ' ' + remove_html(actor_json['name']) | 
					
						
							|  |  |  |         if contains_invalid_chars(bio_str): | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |             print('REJECT: post actor bio contains invalid characters') | 
					
						
							|  |  |  |             return False | 
					
						
							| 
									
										
										
										
											2022-09-25 17:26:11 +00:00
										 |  |  |         if is_filtered_bio(base_dir, nickname, domain, bio_str, | 
					
						
							|  |  |  |                            system_language): | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |             print('REJECT: post actor bio contains filtered text') | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |     else: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |         print('Skipping check for missing bio in ' + sending_actor) | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Check any attached fields for the actor. | 
					
						
							|  |  |  |     # Spam actors will sometimes have attached fields which are all empty | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |     if actor_json.get('attachment'): | 
					
						
							|  |  |  |         if isinstance(actor_json['attachment'], list): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             no_of_tags = 0 | 
					
						
							|  |  |  |             tags_without_value = 0 | 
					
						
							| 
									
										
										
										
											2021-12-26 10:29:52 +00:00
										 |  |  |             for tag in actor_json['attachment']: | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                 if not isinstance(tag, dict): | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2022-05-11 17:39:23 +00:00
										 |  |  |                 if not tag.get('name') and not tag.get('schema:name'): | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                 no_of_tags += 1 | 
					
						
							| 
									
										
										
										
											2022-05-11 17:39:23 +00:00
										 |  |  |                 prop_value_name, _ = get_attachment_property_value(tag) | 
					
						
							|  |  |  |                 if not prop_value_name: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     tags_without_value += 1 | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2022-05-11 17:39:23 +00:00
										 |  |  |                 if not isinstance(tag[prop_value_name], str): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     tags_without_value += 1 | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2022-05-11 17:39:23 +00:00
										 |  |  |                 if not tag[prop_value_name].strip(): | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     tags_without_value += 1 | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2022-05-11 17:39:23 +00:00
										 |  |  |                 if len(tag[prop_value_name]) < 2: | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                     tags_without_value += 1 | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |             if no_of_tags > 0: | 
					
						
							|  |  |  |                 if int(tags_without_value * 100 / no_of_tags) > 50: | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                     print('REJECT: actor has empty attachments ' + | 
					
						
							| 
									
										
										
										
											2022-01-03 14:49:33 +00:00
										 |  |  |                           sending_actor) | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |                     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-13 12:40:09 +00:00
										 |  |  |     # if the actor is valid and was downloaded then | 
					
						
							|  |  |  |     # store it in the cache, but don't write it to file | 
					
						
							|  |  |  |     store_person_in_cache(base_dir, sending_actor, actor_json, | 
					
						
							|  |  |  |                           person_cache, False) | 
					
						
							| 
									
										
										
										
											2021-12-14 13:27:00 +00:00
										 |  |  |     return True | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_featured_hashtags(actor_json: {}) -> str: | 
					
						
							|  |  |  |     """returns a string containing featured hashtags
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     result = '' | 
					
						
							|  |  |  |     if not actor_json.get('tag'): | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |     if not isinstance(actor_json['tag'], list): | 
					
						
							|  |  |  |         return result | 
					
						
							| 
									
										
										
										
											2023-05-03 11:03:00 +00:00
										 |  |  |     ctr = 0 | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  |     for tag_dict in actor_json['tag']: | 
					
						
							|  |  |  |         if not tag_dict.get('type'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not isinstance(tag_dict['type'], str): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not tag_dict['type'].endswith('Hashtag'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not tag_dict.get('name'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not isinstance(tag_dict['name'], str): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not tag_dict.get('href'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not isinstance(tag_dict['href'], str): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         tag_name = tag_dict['name'] | 
					
						
							|  |  |  |         if not tag_name: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if tag_name.startswith('#'): | 
					
						
							|  |  |  |             tag_name = tag_name[1:] | 
					
						
							|  |  |  |         if not tag_name: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2023-07-12 11:08:02 +00:00
										 |  |  |         tag_url = remove_html(tag_dict['href']) | 
					
						
							| 
									
										
										
										
											2023-05-03 10:09:44 +00:00
										 |  |  |         if '://' not in tag_url: | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  |             continue | 
					
						
							|  |  |  |         if not valid_hash_tag(tag_name): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         result += '#' + tag_name + ' ' | 
					
						
							| 
									
										
										
										
											2023-05-03 11:03:00 +00:00
										 |  |  |         ctr += 1 | 
					
						
							|  |  |  |         if ctr >= 10: | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  |     return result.strip() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-03 11:07:34 +00:00
										 |  |  | def get_featured_hashtags_as_html(actor_json: {}, | 
					
						
							|  |  |  |                                   profile_description: str) -> str: | 
					
						
							| 
									
										
										
										
											2023-05-03 10:34:54 +00:00
										 |  |  |     """returns a html string containing featured hashtags
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     result = '' | 
					
						
							|  |  |  |     if not actor_json.get('tag'): | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |     if not isinstance(actor_json['tag'], list): | 
					
						
							|  |  |  |         return result | 
					
						
							| 
									
										
										
										
											2023-05-03 11:03:00 +00:00
										 |  |  |     ctr = 0 | 
					
						
							| 
									
										
										
										
											2023-05-03 10:34:54 +00:00
										 |  |  |     for tag_dict in actor_json['tag']: | 
					
						
							|  |  |  |         if not tag_dict.get('type'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not isinstance(tag_dict['type'], str): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not tag_dict['type'].endswith('Hashtag'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not tag_dict.get('name'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not isinstance(tag_dict['name'], str): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not tag_dict.get('href'): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not isinstance(tag_dict['href'], str): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         tag_name = tag_dict['name'] | 
					
						
							|  |  |  |         if not tag_name: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if tag_name.startswith('#'): | 
					
						
							|  |  |  |             tag_name = tag_name[1:] | 
					
						
							|  |  |  |         if not tag_name: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2023-05-03 11:07:34 +00:00
										 |  |  |         if '/tags/' + tag_name + '"' in profile_description: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if ' #' + tag_name in profile_description: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2023-07-12 11:08:02 +00:00
										 |  |  |         tag_url = remove_html(tag_dict['href']) | 
					
						
							| 
									
										
										
										
											2023-05-03 10:34:54 +00:00
										 |  |  |         if '://' not in tag_url: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not valid_hash_tag(tag_name): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         result += \ | 
					
						
							| 
									
										
										
										
											2023-07-12 11:08:02 +00:00
										 |  |  |             '<a href="' + tag_url + '" ' + \ | 
					
						
							| 
									
										
										
										
											2023-05-03 10:34:54 +00:00
										 |  |  |             'class="mention hashtag" rel="tag" ' + \ | 
					
						
							|  |  |  |             'tabindex="10">#' + tag_name + '</a> ' | 
					
						
							| 
									
										
										
										
											2023-05-03 11:03:00 +00:00
										 |  |  |         ctr += 1 | 
					
						
							|  |  |  |         if ctr >= 10: | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2023-05-03 10:34:54 +00:00
										 |  |  |     result = result.strip() | 
					
						
							|  |  |  |     if result: | 
					
						
							|  |  |  |         result = '<p>' + result + '</p>' | 
					
						
							|  |  |  |     return result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-03 09:54:11 +00:00
										 |  |  | def set_featured_hashtags(actor_json: {}, hashtags: str, | 
					
						
							|  |  |  |                           append: bool = False) -> None: | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  |     """sets featured hashtags
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     separator_str = ' ' | 
					
						
							| 
									
										
										
										
											2023-05-02 22:42:10 +00:00
										 |  |  |     separators = (',', ' ') | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  |     for separator_str in separators: | 
					
						
							|  |  |  |         if separator_str in hashtags: | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |     tag_list = hashtags.split(separator_str) | 
					
						
							| 
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 |  |  |     result: list[str] = [] | 
					
						
							|  |  |  |     tags_used: list[str] = [] | 
					
						
							| 
									
										
										
										
											2023-05-02 22:42:10 +00:00
										 |  |  |     actor_id = actor_json['id'] | 
					
						
							|  |  |  |     actor_domain = actor_id.split('://')[1] | 
					
						
							|  |  |  |     if '/' in actor_domain: | 
					
						
							|  |  |  |         actor_domain = actor_domain.split('/')[0] | 
					
						
							|  |  |  |     actor_url = \ | 
					
						
							|  |  |  |         actor_id.split('://')[0] + '://' + actor_domain | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  |     for tag_str in tag_list: | 
					
						
							|  |  |  |         if not tag_str: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if not tag_str.startswith('#'): | 
					
						
							|  |  |  |             tag_str = '#' + tag_str | 
					
						
							|  |  |  |         if tag_str in tags_used: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2023-05-02 22:42:10 +00:00
										 |  |  |         url = actor_url + '/tags/' + tag_str.replace('#', '') | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  |         result.append({ | 
					
						
							|  |  |  |             "name": tag_str, | 
					
						
							|  |  |  |             "type": "Hashtag", | 
					
						
							|  |  |  |             "href": url | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         tags_used.append(tag_str) | 
					
						
							| 
									
										
										
										
											2023-05-03 11:03:00 +00:00
										 |  |  |         if len(result) >= 10: | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2023-05-02 22:21:03 +00:00
										 |  |  |     # add any non-hashtags to the result | 
					
						
							|  |  |  |     if actor_json.get('tag'): | 
					
						
							|  |  |  |         for tag_dict in actor_json['tag']: | 
					
						
							|  |  |  |             if not tag_dict.get('type'): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if not isinstance(tag_dict['type'], str): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if tag_dict['type'] != 'Hashtag': | 
					
						
							|  |  |  |                 result.append(tag_dict) | 
					
						
							| 
									
										
										
										
											2023-05-03 09:54:11 +00:00
										 |  |  |     if not append: | 
					
						
							|  |  |  |         actor_json['tag'] = result | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         actor_json['tag'] += result | 
					
						
							| 
									
										
										
										
											2023-09-01 09:22:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def update_memorial_flags(base_dir: str, person_cache: {}) -> None: | 
					
						
							|  |  |  |     """Sets or clears the memorial flags based upon the content of
 | 
					
						
							|  |  |  |     accounts/memorial file | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     memorials = get_memorials(base_dir).split('\n') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |     dir_str = data_dir(base_dir) | 
					
						
							|  |  |  |     for _, dirs, _ in os.walk(dir_str): | 
					
						
							| 
									
										
										
										
											2023-09-01 09:22:38 +00:00
										 |  |  |         for account in dirs: | 
					
						
							|  |  |  |             if not is_account_dir(account): | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |             actor_filename = data_dir(base_dir) + '/' + account + '.json' | 
					
						
							| 
									
										
										
										
											2023-09-01 09:22:38 +00:00
										 |  |  |             if not os.path.isfile(actor_filename): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             actor_json = load_json(actor_filename) | 
					
						
							|  |  |  |             if not actor_json: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if not actor_json.get('id'): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             nickname = account.split('@')[0] | 
					
						
							|  |  |  |             actor_changed = False | 
					
						
							|  |  |  |             if not actor_json.get('memorial'): | 
					
						
							|  |  |  |                 if nickname in memorials: | 
					
						
							|  |  |  |                     actor_json['memorial'] = True | 
					
						
							|  |  |  |                     actor_changed = True | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 if nickname not in memorials: | 
					
						
							|  |  |  |                     actor_json['memorial'] = False | 
					
						
							|  |  |  |                     actor_changed = True | 
					
						
							| 
									
										
										
										
											2023-09-01 09:32:33 +00:00
										 |  |  |             if not actor_changed: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             save_json(actor_json, actor_filename) | 
					
						
							|  |  |  |             actor = actor_json['id'] | 
					
						
							|  |  |  |             remove_person_from_cache(base_dir, actor, person_cache) | 
					
						
							|  |  |  |             store_person_in_cache(base_dir, actor, actor_json, | 
					
						
							|  |  |  |                                   person_cache, True) | 
					
						
							| 
									
										
										
										
											2023-09-01 09:22:38 +00:00
										 |  |  |         break | 
					
						
							| 
									
										
										
										
											2024-01-29 21:45:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_account_pub_key(path: str, person_cache: {}, | 
					
						
							|  |  |  |                         base_dir: str, domain: str, | 
					
						
							|  |  |  |                         calling_domain: str, | 
					
						
							|  |  |  |                         http_prefix: str, | 
					
						
							|  |  |  |                         domain_full: str, | 
					
						
							|  |  |  |                         onion_domain: str, | 
					
						
							|  |  |  |                         i2p_domain: str) -> str: | 
					
						
							|  |  |  |     """Returns the public key for an account
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if '/users/' not in path: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     nickname = path.split('/users/')[1] | 
					
						
							|  |  |  |     if '#main-key' in nickname: | 
					
						
							|  |  |  |         nickname = nickname.split('#main-key')[0] | 
					
						
							|  |  |  |     elif '/main-key' in nickname: | 
					
						
							|  |  |  |         nickname = nickname.split('/main-key')[0] | 
					
						
							|  |  |  |     elif '#/publicKey' in nickname: | 
					
						
							|  |  |  |         nickname = nickname.split('#/publicKey')[0] | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     actor = \ | 
					
						
							|  |  |  |         get_instance_url(calling_domain, | 
					
						
							|  |  |  |                          http_prefix, | 
					
						
							|  |  |  |                          domain_full, | 
					
						
							|  |  |  |                          onion_domain, | 
					
						
							|  |  |  |                          i2p_domain) + \ | 
					
						
							|  |  |  |         '/users/' + nickname | 
					
						
							|  |  |  |     actor_json = get_person_from_cache(base_dir, actor, person_cache) | 
					
						
							|  |  |  |     if not actor_json: | 
					
						
							|  |  |  |         actor_filename = acct_dir(base_dir, nickname, domain) + '.json' | 
					
						
							|  |  |  |         if not os.path.isfile(actor_filename): | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2024-06-20 10:47:58 +00:00
										 |  |  |         actor_json = load_json(actor_filename) | 
					
						
							| 
									
										
										
										
											2024-01-29 21:45:04 +00:00
										 |  |  |         if not actor_json: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         store_person_in_cache(base_dir, actor, actor_json, | 
					
						
							|  |  |  |                               person_cache, False) | 
					
						
							|  |  |  |     if not actor_json.get('publicKey') and \ | 
					
						
							|  |  |  |        not actor_json.get('assertionMethod'): | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     original_person_url = \ | 
					
						
							|  |  |  |         get_instance_url(calling_domain, | 
					
						
							|  |  |  |                          http_prefix, | 
					
						
							|  |  |  |                          domain_full, | 
					
						
							|  |  |  |                          onion_domain, | 
					
						
							|  |  |  |                          i2p_domain) + \ | 
					
						
							|  |  |  |         path | 
					
						
							|  |  |  |     pub_key, _ = \ | 
					
						
							|  |  |  |         get_actor_public_key_from_id(actor_json, original_person_url) | 
					
						
							|  |  |  |     return pub_key |