diff --git a/src/daemon_post_profile.py b/src/daemon_post_profile.py index 17f878e1c..d2b7dab36 100644 --- a/src/daemon_post_profile.py +++ b/src/daemon_post_profile.py @@ -126,6 +126,8 @@ from src.lxmf import get_lxmf_address from src.lxmf import set_lxmf_address from src.briar import get_briar_address from src.briar import set_briar_address +from src.ricochet import get_ricochet_address +from src.ricochet import set_ricochet_address from src.cwtch import get_cwtch_address from src.cwtch import set_cwtch_address from src.enigma import get_enigma_pub_key @@ -1780,6 +1782,23 @@ def _profile_post_briar_address(fields: {}, actor_json: {}, return actor_changed +def _profile_post_ricochet_address(fields: {}, actor_json: {}, + actor_changed: bool) -> bool: + """ HTTP POST change ricochet address + """ + current_ricochet_address = get_ricochet_address(actor_json) + if fields.get('ricochetAddress'): + if fields['ricochetAddress'] != current_ricochet_address: + set_briar_address(actor_json, + fields['ricochetAddress']) + actor_changed = True + else: + if current_ricochet_address: + set_ricochet_address(actor_json, '') + actor_changed = True + return actor_changed + + def _profile_post_tox_address(fields: {}, actor_json: {}, actor_changed: bool) -> bool: """ HTTP POST change tox address @@ -3075,6 +3094,10 @@ def profile_edit(self, calling_domain: str, cookie: str, _profile_post_briar_address(fields, actor_json, actor_changed) + actor_changed = \ + _profile_post_ricochet_address(fields, actor_json, + actor_changed) + actor_changed = \ _profile_post_cwtch_address(fields, actor_json, actor_changed) diff --git a/src/daemon_utils.py b/src/daemon_utils.py index 50cdf7437..bf72e289c 100644 --- a/src/daemon_utils.py +++ b/src/daemon_utils.py @@ -66,6 +66,7 @@ from src.blog import get_blog_address from src.tox import get_tox_address from src.lxmf import get_lxmf_address from src.briar import get_briar_address +from src.ricochet import get_ricochet_address from src.cwtch import get_cwtch_address from src.pgp import get_pgp_fingerprint from src.pgp import get_email_address @@ -712,6 +713,7 @@ def show_person_options(self, calling_domain: str, path: str, tox_address = None lxmf_address = None briar_address = None + ricochet_address = None cwtch_address = None ssb_address = None email_address = None @@ -761,6 +763,7 @@ def show_person_options(self, calling_domain: str, path: str, tox_address = get_tox_address(actor_json) lxmf_address = get_lxmf_address(actor_json) briar_address = get_briar_address(actor_json) + ricochet_address = get_ricochet_address(actor_json) cwtch_address = get_cwtch_address(actor_json) email_address = get_email_address(actor_json) deltachat_invite = \ @@ -819,7 +822,7 @@ def show_person_options(self, calling_domain: str, path: str, xmpp_address, matrix_address, ssb_address, blog_address, tox_address, lxmf_address, - briar_address, + briar_address, ricochet_address, cwtch_address, enigma_pub_key, pgp_pub_key, pgp_fingerprint, diff --git a/src/pgp.py b/src/pgp.py index 167f8cedd..111767043 100644 --- a/src/pgp.py +++ b/src/pgp.py @@ -37,6 +37,7 @@ from src.loops import get_loops from src.xmpp import get_xmpp_address from src.matrix import get_matrix_address from src.briar import get_briar_address +from src.ricochet import get_ricochet_address from src.cwtch import get_cwtch_address from src.blog import get_blog_address from src.website import get_website @@ -967,6 +968,11 @@ def actor_to_vcard(actor: {}, domain: str, translate: {}, if briar_address.startswith('briar://'): briar_address = briar_address.split('briar://')[1] vcard_str += 'IMPP:briar:' + briar_address + '\n' + ricochet_address = get_ricochet_address(actor) + if ricochet_address: + if ricochet_address.startswith('ricochet:'): + ricochet_address = ricochet_address.split('ricochet:')[1] + vcard_str += 'IMPP:ricochet:' + ricochet_address + '\n' cwtch_address = get_cwtch_address(actor) if cwtch_address: vcard_str += 'IMPP:cwtch:' + cwtch_address + '\n' @@ -1094,6 +1100,11 @@ def actor_to_vcard_xml(actor: {}, domain: str, translate: {}, vcard_str += ' ' + \ 'briar' + \ '' + briar_address + '\n' + ricochet_address = get_ricochet_address(actor) + if ricochet_address: + vcard_str += ' ' + \ + 'ricochet' + \ + '' + ricochet_address + '\n' cwtch_address = get_cwtch_address(actor) if cwtch_address: vcard_str += ' ' + \ diff --git a/src/ricochet.py b/src/ricochet.py new file mode 100644 index 000000000..f7bfceb1e --- /dev/null +++ b/src/ricochet.py @@ -0,0 +1,149 @@ +__filename__ = "ricochet.py" +__author__ = "Bob Mottram" +__license__ = "AGPL3+" +__version__ = "1.7.0" +__maintainer__ = "Bob Mottram" +__email__ = "bob@libreserver.org" +__status__ = "Production" +__module_group__ = "Profile Metadata" + + +from src.utils import get_attachment_property_value +from src.utils import remove_html + + +def get_ricochet_address(actor_json: {}) -> str: + """Returns ricochet address for the given actor + """ + if not actor_json.get('attachment'): + return '' + if not isinstance(actor_json['attachment'], list): + return '' + for property_value in actor_json['attachment']: + if not isinstance(property_value, dict): + print("WARN: actor attachment is not dict: " + str(property_value)) + continue + name_value: str = None + if property_value.get('name'): + if isinstance(property_value['name'], str): + name_value = property_value['name'] + elif property_value.get('schema:name'): + if isinstance(property_value['schema:name'], str): + name_value = property_value['schema:name'] + if not name_value: + continue + if not name_value.lower().startswith('ricochet'): + continue + if not property_value.get('type'): + continue + if not isinstance(property_value['type'], str): + continue + prop_value_name, prop_value = \ + get_attachment_property_value(property_value) + if not prop_value: + continue + if not property_value['type'].endswith('PropertyValue'): + continue + property_value[prop_value_name] = prop_value.strip() + if len(property_value[prop_value_name]) < 60: + continue + if not property_value[prop_value_name].startswith('ricochet:'): + continue + if property_value[prop_value_name].lower() != \ + property_value[prop_value_name]: + continue + if '"' in property_value[prop_value_name]: + continue + if ' ' in property_value[prop_value_name]: + continue + if ',' in property_value[prop_value_name]: + continue + if '.' in property_value[prop_value_name]: + continue + return remove_html(property_value[prop_value_name]) + return '' + + +def set_ricochet_address(actor_json: {}, ricochet_address: str) -> None: + """Sets an ricochet address for the given actor + """ + not_ricochet_address: bool = False + + if len(ricochet_address) < 60: + not_ricochet_address = True + if not ricochet_address.startswith('ricochet:'): + not_ricochet_address = True + if ricochet_address.lower() != ricochet_address: + not_ricochet_address = True + if '"' in ricochet_address: + not_ricochet_address = True + if ' ' in ricochet_address: + not_ricochet_address = True + if '.' in ricochet_address: + not_ricochet_address = True + if ',' in ricochet_address: + not_ricochet_address = True + if '<' in ricochet_address: + not_ricochet_address = True + + if not actor_json.get('attachment'): + actor_json['attachment']: list[dict] = [] + + # remove any existing value + property_found: dict = None + for property_value in actor_json['attachment']: + if not isinstance(property_value, dict): + print("WARN: actor attachment is not dict: " + str(property_value)) + continue + name_value: str = None + if property_value.get('name'): + name_value = property_value['name'] + elif property_value.get('schema:name'): + name_value = property_value['schema:name'] + if not name_value: + continue + if not property_value.get('type'): + continue + if not name_value.lower().startswith('ricochet'): + continue + property_found = property_value + break + if property_found: + actor_json['attachment'].remove(property_found) + if not_ricochet_address: + return + + for property_value in actor_json['attachment']: + if not isinstance(property_value, dict): + print("WARN: actor attachment is not dict: " + str(property_value)) + continue + name_value: str = None + if property_value.get('name'): + if isinstance(property_value['name'], str): + name_value = property_value['name'] + elif property_value.get('schema:name'): + if isinstance(property_value['schema:name'], str): + name_value = property_value['schema:name'] + if not name_value: + continue + if not property_value.get('type'): + continue + if not isinstance(property_value['type'], str): + continue + if not name_value.lower().startswith('ricochet'): + continue + if not property_value['type'].endswith('PropertyValue'): + continue + prop_value_name, _ = \ + get_attachment_property_value(property_value) + if not prop_value_name: + continue + property_value[prop_value_name] = ricochet_address + return + + new_ricochet_address = { + "name": "Ricochet", + "type": "PropertyValue", + "value": ricochet_address + } + actor_json['attachment'].append(new_ricochet_address) diff --git a/src/webapp_person_options.py b/src/webapp_person_options.py index 8899b761d..8a81c359c 100644 --- a/src/webapp_person_options.py +++ b/src/webapp_person_options.py @@ -148,6 +148,7 @@ def html_person_options(default_timeline: str, tox_address: str, lxmf_address: str, briar_address: str, + ricochet_address: str, cwtch_address: str, enigma_pub_key: str, pgp_pub_key: str, @@ -519,6 +520,15 @@ def html_person_options(default_timeline: str, options_str += \ '

briar://' + \ remove_html(briar_address) + '

\n' + if ricochet_address: + if ricochet_address.startswith('ricochet:'): + options_str += \ + '

' + \ + remove_html(ricochet_address) + '

\n' + else: + options_str += \ + '

briar://' + \ + remove_html(ricochet_address) + '

\n' if cwtch_address: options_str += \ '

Cwtch: ' + \ diff --git a/src/webapp_profile.py b/src/webapp_profile.py index 376b28e6c..2656df574 100644 --- a/src/webapp_profile.py +++ b/src/webapp_profile.py @@ -94,6 +94,7 @@ from src.enigma import get_enigma_pub_key from src.tox import get_tox_address from src.lxmf import get_lxmf_address from src.briar import get_briar_address +from src.ricochet import get_ricochet_address from src.cwtch import get_cwtch_address from src.filters import is_filtered from src.follow import is_follower_of_person @@ -1337,6 +1338,7 @@ def html_profile(signing_priv_key_pem: str, tox_address: str = get_tox_address(profile_json) lxmf_address: str = get_lxmf_address(profile_json) briar_address: str = get_briar_address(profile_json) + ricochet_address: str = get_ricochet_address(profile_json) cwtch_address: str = get_cwtch_address(profile_json) verified_site_checkmark: str = '✔' premium: bool = is_premium_account(base_dir, nickname, domain) @@ -1344,6 +1346,7 @@ def html_profile(signing_priv_key_pem: str, art_site_url or music_site_url or youtube or peertube or \ loops or pixelfed or xmpp_address or matrix_address or \ ssb_address or tox_address or lxmf_address or briar_address or \ + ricochet_address or \ cwtch_address or pgp_pub_key or enigma_pub_key or pgp_fingerprint or \ email_address or deltachat_invite: donate_section = '

\n' @@ -1477,6 +1480,15 @@ def html_profile(signing_priv_key_pem: str, donate_section += \ '

briar://

\n' + if ricochet_address: + if ricochet_address.startswith('ricochet:'): + donate_section += \ + '

\n' + else: + donate_section += \ + '

ricochet:

\n' if cwtch_address: donate_section += \ '

Cwtch: