diff --git a/README.md b/README.md index d007957b7..d7319bf5e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Epicyon is a [fediverse](https://en.wikipedia.org/wiki/Fediverse) server suitabl Key features: - * Open standards: HTML, CSS, ActivityPub, RSS, CalDAV. + * Open standards: HTML, CSS, ActivityPub S2S and C2S, RSS, CalDAV. * Supports common web browsers and [shell browsers](https://lynx.invisible-island.net). * Will not drain your mobile or laptop battery. * Customisable themes. It doesn't have to look bland. diff --git a/gemini/EN/index.gmi b/gemini/EN/index.gmi index 22da095ca..31a001ede 100644 --- a/gemini/EN/index.gmi +++ b/gemini/EN/index.gmi @@ -17,7 +17,7 @@ Epicyon is a fediverse server suitable for self-hosting a small number of accoun Key features: - * Open standards: HTML, CSS, ActivityPub, RSS, CalDAV. + * Open standards: HTML, CSS, ActivityPub S2S and C2S, RSS, CalDAV. * Supports common web browsers and shell browsers. * Will not drain your mobile or laptop battery. * Customisable themes. It doesn't have to look bland. diff --git a/inbox.py b/inbox.py index 380290536..a01d73764 100644 --- a/inbox.py +++ b/inbox.py @@ -18,6 +18,7 @@ from languages import understood_post_language from like import update_likes_collection from reaction import update_reaction_collection from reaction import valid_emoji_content +from utils import is_quote_toot from utils import acct_handle_dir from utils import is_account_dir from utils import remove_eol @@ -656,6 +657,10 @@ def save_post_to_inbox_queue(base_dir: str, http_prefix: str, post_domain = get_full_domain(post_domain, post_port) if has_object_dict(post_json_object): + if is_quote_toot(post_json_object): + if debug: + print('REJECT: inbox quote toot ' + str(post_json_object)) + return None if post_json_object['object'].get('inReplyTo'): if isinstance(post_json_object['object']['inReplyTo'], str): in_reply_to = \ diff --git a/manual/manual.md b/manual/manual.md index ea9329014..328d5f1a6 100644 --- a/manual/manual.md +++ b/manual/manual.md @@ -31,7 +31,7 @@ The word *fediverse* (federated universe) appears to have originated around 2012 Servers such as [Mastodon](https://github.com/mastodon/mastodon) are well known, but these are aimed at large scale deployments on powerful hardware running within data centers, making use of content distribution networks (CDN) and due to their large number of dependencies requiring someone with a high level of systems administration skill to maintain. Epicyon is designed for the opposite situation where it is only intended to have a single user or a small number of users (less than ten) running from your home location or on a modest VPS and where maintenance is extremely trivial such that it's possible to keep an instance running for long durations with minimal intervention. -Epicyon is part of the [small web](https://neustadt.fr/essays/the-small-web) category of internet software, in that it is intended to scale via federation rather than to scale vertically via resource intensive and expensive hardware. Think many small communicating nodes rather than a small number of large servers. Also, in spite of the prevailing great obsession with scale, not everything needs to. You can federate with a small number of servers for a particular purpose - such as running a club or hackspace - and that's ok. +Epicyon is part of the [small web](https://neustadt.fr/essays/the-small-web) category of internet software, in that it is intended to scale via federation rather than to scale vertically via resource intensive and expensive hardware. Think many small communicating nodes rather than a small number of large servers. Also, in spite of the prevailing great obsession with scale, not everything needs to. You can federate with a small number of servers for a particular purpose - such as running a club or hackspace - and that's ok. It supports both the server-to-server (S2S) and client-to-server (C2S) versions of the ActivityPub protocol, with [basic auth](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication) for C2S authentication. [Anti-virality](https://uxdesign.cc/mastodon-is-antiviral-design-42f090ab8d51?gi=9baf6195c60b) is a common design approach in the fediverse, and Epicyon also follows this convention by having chronological timelines and avoiding lists of trending things or ranking profiles by numbers of followers. Recent hashtags are presented *in alphabetical order* to avoid any frequency bias. Typically if a post gets more than ten likes then its count will only show as *"10+"*, to try to avoid getting fixated upon making numbers go up at the expense of more considered forms of interaction. diff --git a/outbox.py b/outbox.py index 4132a808f..f603d450f 100644 --- a/outbox.py +++ b/outbox.py @@ -31,6 +31,7 @@ from utils import save_json from utils import acct_dir from utils import local_actor_url from utils import has_actor +from utils import is_quote_toot from blocking import is_blocked_domain from blocking import outbox_block from blocking import outbox_undo_block @@ -263,6 +264,10 @@ def post_message_to_outbox(session, translate: {}, # check that the outgoing post doesn't contain any markup # which can be used to implement exploits if has_object_dict(message_json): + if is_quote_toot(message_json): + print('REJECT: POST quote toot ' + str(message_json)) + return False + content_str = get_base_content_from_post(message_json, system_language) if content_str: _capitalize_hashtag(content_str, message_json, diff --git a/utils.py b/utils.py index a6261426b..cd623167f 100644 --- a/utils.py +++ b/utils.py @@ -4127,3 +4127,32 @@ def save_reverse_timeline(base_dir: str, reverse_sequence: []) -> []: print('EX: failed to delete reverse ' + reverse_filename) break + + +def is_quote_toot(post_json_object: str) -> bool: + """Returns true if the given post is a quote toot + """ + # Pleroma implementation + if post_json_object['object'].get('quoteUri') or \ + post_json_object['object'].get('quoteUrl'): + return True + # More correct ActivityPub implementation + if post_json_object['object'].get('tag'): + if isinstance(post_json_object['object']['tag'], list): + for item in post_json_object['object']['tag']: + if not isinstance(item, dict): + continue + if not item.get('type'): + continue + if not item.get('mediaType'): + continue + if not isinstance(item['type'], str): + continue + if item['type'] != 'Link': + continue + if not isinstance(item['mediaType'], str): + continue + if 'json' not in item['mediaType']: + continue + return True + return False diff --git a/webapp_post.py b/webapp_post.py index 98ff74049..9dc94656e 100644 --- a/webapp_post.py +++ b/webapp_post.py @@ -2917,6 +2917,7 @@ def html_conversation_thread(post_id: str, html_header_with_external_style(css_filename, instance_title, None) separator_str = html_post_separator(base_dir, None) + text_mode_separator = '

' minimize_all_images = False if nickname in min_images_for_accounts: @@ -2951,7 +2952,7 @@ def html_conversation_thread(post_id: str, dogwhistles, minimize_all_images) if post_str: - conv_str += separator_str + post_str + conv_str += text_mode_separator + separator_str + post_str - conv_str += html_footer() + conv_str += text_mode_separator + html_footer() return conv_str diff --git a/website/EN/index.html b/website/EN/index.html index 30f911b2c..5db88e768 100644 --- a/website/EN/index.html +++ b/website/EN/index.html @@ -1198,7 +1198,7 @@

Key features: