diff --git a/daemon_get.py b/daemon_get.py index 5878a18f4..412a1d070 100644 --- a/daemon_get.py +++ b/daemon_get.py @@ -453,7 +453,8 @@ def daemon_http_get(self) -> None: if show_vcard(self, self.server.base_dir, self.path, calling_domain, referer_domain, - self.server.domain, self.server.translate): + self.server.domain, self.server.translate, + self.server.system_language): return # getting the public key for an account diff --git a/daemon_get_vcard.py b/daemon_get_vcard.py index a2908a13c..b9ac57173 100644 --- a/daemon_get_vcard.py +++ b/daemon_get_vcard.py @@ -22,7 +22,8 @@ from data import is_a_file def show_vcard(self, base_dir: str, path: str, calling_domain: str, - referer_domain: str, domain: str, translate: {}) -> bool: + referer_domain: str, domain: str, translate: {}, + system_language: str) -> bool: """Returns a vcard for the given account """ if not has_accept(self, calling_domain): @@ -68,10 +69,12 @@ def show_vcard(self, base_dir: str, path: str, calling_domain: str, self.server.vcard_is_active = False return True if 'application/vcard+xml' in accept_str: - vcard_str = actor_to_vcard_xml(actor_json, domain, translate) + vcard_str = \ + actor_to_vcard_xml(actor_json, domain, translate, system_language) header_type = 'application/vcard+xml; charset=utf-8' else: - vcard_str = actor_to_vcard(actor_json, domain, translate) + vcard_str = \ + actor_to_vcard(actor_json, domain, translate, system_language) header_type = 'text/vcard; charset=utf-8' if vcard_str: msg = vcard_str.encode('utf-8') diff --git a/daemon_post_profile.py b/daemon_post_profile.py index de888532c..3c589d95f 100644 --- a/daemon_post_profile.py +++ b/daemon_post_profile.py @@ -180,7 +180,8 @@ def _profile_post_save_actor(base_dir: str, http_prefix: str, curr_session, proxy_type: str, send_move_activity: bool, self, cached_webfingers: {}, - person_cache: {}, project_version: str) -> None: + person_cache: {}, project_version: str, + system_language: str) -> None: """ HTTP POST save actor json file within accounts """ add_name_emojis_to_tags(base_dir, http_prefix, @@ -198,7 +199,7 @@ def _profile_post_save_actor(base_dir: str, http_prefix: str, actor_json['featured'] = actor_json['id'] + '/collections/featured' if not actor_json.get('featuredTags'): actor_json['featuredTags'] = actor_json['id'] + '/collections/tags' - randomize_actor_images(actor_json) + randomize_actor_images(actor_json, system_language) add_actor_update_timestamp(actor_json) # save the actor save_json(actor_json, actor_filename) @@ -3361,7 +3362,8 @@ def profile_edit(self, calling_domain: str, cookie: str, curr_session, proxy_type, send_move_activity, self, cached_webfingers, - person_cache, project_version) + person_cache, project_version, + system_language) if _profile_post_deactivate_account(base_dir, nickname, domain, calling_domain, diff --git a/mastoapiv1.py b/mastoapiv1.py index 72bfefc7b..ded38207f 100644 --- a/mastoapiv1.py +++ b/mastoapiv1.py @@ -21,6 +21,7 @@ from utils import lines_in_file from utils import data_dir from utils import account_is_indexable from utils import is_yggdrasil_address +from utils import get_preferred_username from data import load_list from data import load_string from data import is_a_file @@ -75,9 +76,8 @@ def _meta_data_instance_v1(show_accounts: bool, elif admin_actor['type'] != 'Person': is_bot = True - url = \ - http_prefix + '://' + domain_full + '/@' + \ - admin_actor['preferredUsername'] + preferred_username = get_preferred_username(admin_actor, system_language) + url = http_prefix + '://' + domain_full + '/@' + preferred_username if show_accounts: active_accounts: int = no_of_accounts(base_dir) @@ -112,7 +112,7 @@ def _meta_data_instance_v1(show_accounts: bool, 'locked': admin_actor['manuallyApprovesFollowers'], 'note': '

Admin of ' + domain + '

', 'url': url, - 'username': admin_actor['preferredUsername'] + 'username': preferred_username }, 'description': instance_description, 'languages': [system_language], diff --git a/mastoapiv2.py b/mastoapiv2.py index 17373b5a6..b2835a18c 100644 --- a/mastoapiv2.py +++ b/mastoapiv2.py @@ -19,6 +19,7 @@ from utils import lines_in_file from utils import data_dir from utils import account_is_indexable from utils import is_yggdrasil_address +from utils import get_preferred_username from formats import get_image_mime_type from formats import get_image_extensions from formats import get_audio_extensions @@ -82,9 +83,8 @@ def _meta_data_instance_v2(show_accounts: bool, elif admin_actor['type'] != 'Person': is_bot = True - url = \ - http_prefix + '://' + domain_full + '/@' + \ - admin_actor['preferredUsername'] + preferred_username = get_preferred_username(admin_actor, system_language) + url = http_prefix + '://' + domain_full + '/@' + preferred_username if show_accounts: active_accounts: int = no_of_accounts(base_dir) diff --git a/person.py b/person.py index 45e5eede7..97a8e888f 100644 --- a/person.py +++ b/person.py @@ -40,6 +40,7 @@ from media import process_meta_data from flags import is_image_file from timeFunctions import date_utcnow from timeFunctions import get_current_time_int +from utils import get_preferred_username from utils import string_starts_with from utils import is_yggdrasil_address from utils import get_person_icon @@ -201,7 +202,7 @@ def _account_exists(base_dir: str, nickname: str, domain: str) -> bool: is_a_dir(base_dir + '/deactivated/' + nickname + '@' + domain) -def randomize_actor_images(person_json: {}) -> None: +def randomize_actor_images(person_json: {}, system_language: str) -> None: """Randomizes the filenames for avatar image and background This causes other instances to update their cached avatar image """ @@ -213,7 +214,7 @@ def randomize_actor_images(person_json: {}) -> None: # secure names rand_str = str(randint(10000000000000, 99999999999999)) # nosec base_url = person_id.split('/users/')[0] - nickname = person_json['preferredUsername'] + nickname = get_preferred_username(person_json, system_language) person_json['icon']['url'] = \ base_url + '/system/accounts/avatars/' + nickname + \ '/avatar' + rand_str + '.' + existing_extension @@ -246,7 +247,7 @@ def get_actor_update_json(actor_json: {}) -> {}: if actor_json.get('attributionDomains'): if isinstance(actor_json['attributionDomains'], list): attribution_domains = actor_json['attributionDomains'] - return { + actor_update: dict = { '@context': [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", @@ -362,6 +363,10 @@ def get_actor_update_json(actor_json: {}) -> {}: "publicKey": actor_json['publicKey'] } } + if 'preferredUsernameMap' in actor_json: + actor_update['preferredUsernameMap'] = \ + actor_json['preferredUsernameMap'] + return actor_update def get_actor_move_json(actor_json: {}) -> {}: @@ -2175,6 +2180,14 @@ def valid_sending_actor(session, base_dir: str, sending_actor + ' ' + bio_str) return False bio_str += ' ' + remove_html(actor_json['preferredUsername']) + # include the username map + if 'preferredUsernameMap' in actor_json: + username_map = actor_json['preferredUsernameMap'] + if isinstance(username_map, dict): + for _, preferred_username in username_map.items(): + if not isinstance(preferred_username, str): + continue + bio_str += ' ' + remove_html(preferred_username) if actor_json.get('attachment'): if isinstance(actor_json['attachment'], list): diff --git a/pgp.py b/pgp.py index a3c7892f0..412a73ff9 100644 --- a/pgp.py +++ b/pgp.py @@ -14,6 +14,7 @@ from person import get_actor_json from flags import is_pgp_encrypted from flags import contains_pgp_public_key from occupation import get_occupation_skills +from utils import get_preferred_username from utils import get_url_from_post from utils import safe_system_string from utils import get_full_domain @@ -889,15 +890,17 @@ def pgp_public_key_upload(base_dir: str, session, return actor_update -def actor_to_vcard(actor: {}, domain: str, translate: {}) -> str: +def actor_to_vcard(actor: {}, domain: str, translate: {}, + system_language: str) -> str: """Returns a vcard for a given actor """ actor_url_str = get_url_from_post(actor['url']) + preferred_username = get_preferred_username(actor, system_language) vcard_str = 'BEGIN:VCARD\n' vcard_str += 'VERSION:4.0\n' vcard_str += 'REV:' + actor['published'] + '\n' vcard_str += 'FN:' + remove_html(actor['name']) + '\n' - vcard_str += 'NICKNAME:' + actor['preferredUsername'] + '\n' + vcard_str += 'NICKNAME:' + preferred_username + '\n' vcard_str += 'NOTE:' + remove_html(actor['summary']) + '\n' url_str = get_url_from_post(actor['icon']['url']) if url_str: @@ -909,8 +912,7 @@ def actor_to_vcard(actor: {}, domain: str, translate: {}) -> str: email_address = get_email_address(actor) if email_address: vcard_str += 'EMAIL;TYPE=internet:' + email_address + '\n' - vcard_str += 'IMPP:fediverse:' + \ - actor['preferredUsername'] + '@' + domain + '\n' + vcard_str += 'IMPP:fediverse:' + preferred_username + '@' + domain + '\n' if actor.get('vcard:bday'): birthday_str = actor['vcard:bday'] if '-' in birthday_str: @@ -1004,16 +1006,18 @@ def actor_to_vcard(actor: {}, domain: str, translate: {}) -> str: return vcard_str -def actor_to_vcard_xml(actor: {}, domain: str, translate: {}) -> str: +def actor_to_vcard_xml(actor: {}, domain: str, translate: {}, + system_language: str) -> str: """Returns a xml formatted vcard for a given actor """ + preferred_username = get_preferred_username(actor, system_language) vcard_str = '\n' vcard_str += '\n' vcard_str += ' \n' vcard_str += ' ' + \ remove_html(actor['name']) + '\n' vcard_str += ' ' + \ - actor['preferredUsername'] + '\n' + preferred_username + '\n' vcard_str += ' ' + \ remove_html(actor['summary']) + '\n' email_address = get_email_address(actor) @@ -1021,7 +1025,7 @@ def actor_to_vcard_xml(actor: {}, domain: str, translate: {}) -> str: vcard_str += ' ' + email_address + '\n' vcard_str += ' ' + \ 'fediverse' + \ - '' + actor['preferredUsername'] + '@' + domain + \ + '' + preferred_username + '@' + domain + \ '\n' if actor.get('vcard:bday'): birthday_str = actor['vcard:bday'] diff --git a/posts.py b/posts.py index 462aa786b..521a1ffff 100644 --- a/posts.py +++ b/posts.py @@ -5227,6 +5227,7 @@ def _novel_fields_for_person(nickname: str, domain: str, 'name', 'outbox', 'preferredUsername', + 'preferredUsernameMap', 'publicKey', 'summary', 'tag', diff --git a/utils.py b/utils.py index 241a1886c..78e003e71 100644 --- a/utils.py +++ b/utils.py @@ -4343,3 +4343,16 @@ def is_private_browser(ua_str: str) -> bool: ('librewolf', 'privacy', 'private')): return True return False + + +def get_preferred_username(actor: {}, system_language: str) -> str: + """Returns the preferred username from the given actor + """ + if 'preferredUsernameMap' in actor: + if isinstance(actor['preferredUsernameMap'], dict): + if actor['preferredUsernameMap'].get(system_language): + username: str = \ + actor['preferredUsernameMap'][system_language] + if isinstance(username, str): + return username + return actor['preferredUsername'] diff --git a/webapp_frontscreen.py b/webapp_frontscreen.py index 3b9f062dc..deeeddf13 100644 --- a/webapp_frontscreen.py +++ b/webapp_frontscreen.py @@ -11,6 +11,7 @@ from flags import is_system_account from utils import get_mutuals_of_person from utils import get_domain_from_actor from utils import get_config_param +from utils import get_preferred_username from timeFunctions import get_account_timezone from person import person_box_json from webapp_utils import html_header_with_external_style @@ -161,7 +162,7 @@ def html_front_screen(signing_priv_key_pem: str, """Show the news instance front screen """ bold_reading: bool = False - nickname = profile_json['preferredUsername'] + nickname: str = get_preferred_username(profile_json, system_language) if not nickname: return "" if not is_system_account(nickname): @@ -169,7 +170,7 @@ def html_front_screen(signing_priv_key_pem: str, domain, port = get_domain_from_actor(profile_json['id']) if not domain: return "" - domain_full = domain + domain_full: str = domain if port: domain_full = domain + ':' + str(port) diff --git a/webapp_profile.py b/webapp_profile.py index ba761a8bc..cf563c661 100644 --- a/webapp_profile.py +++ b/webapp_profile.py @@ -22,6 +22,7 @@ from textmode import text_mode_removals from unicodetext import uninvert_text from unicodetext import standardize_text from occupation import get_occupation_name +from utils import get_preferred_username from utils import is_private_browser from utils import replace_embedded_map_with_link from utils import is_yggdrasil_address @@ -1198,7 +1199,7 @@ def html_profile(signing_priv_key_pem: str, if is_a_file(moved_accounts_filename): show_moved_accounts = True - nickname: str = profile_json['preferredUsername'] + nickname: str = get_preferred_username(profile_json, system_language) if not nickname: return "" if is_system_account(nickname): diff --git a/webapp_utils.py b/webapp_utils.py index 1eb12c5bf..354dde521 100644 --- a/webapp_utils.py +++ b/webapp_utils.py @@ -15,6 +15,7 @@ from session import get_json_valid from flags import is_float from flags import is_moderator from formats import media_file_mime_type +from utils import get_preferred_username from utils import replace_embedded_map_with_link from utils import chatbot_nicknames from utils import replace_strings @@ -901,7 +902,8 @@ def html_header_with_person_markup(css_filename: str, instance_title: str, description = remove_html(actor_json['summary']) name_str: str = remove_html(actor_json['name']) domain_full: str = actor_json['id'].split('://')[1].split('/')[0] - handle: str = actor_json['preferredUsername'] + '@' + domain_full + handle: str = \ + get_preferred_username(actor_json, lang) + '@' + domain_full url_str: str = get_url_from_post(actor_json['icon']['url']) icon_url: str = remove_html(url_str)