Merge branch 'dev' into nomadic

This commit is contained in:
Mike Macgirvin 2024-05-29 08:00:23 +10:00
commit 37a0582886
10 changed files with 549 additions and 513 deletions

View file

@ -20,12 +20,36 @@ Supported activities:
Many other activity combinations we've seen in the wild are partially supported. If you're looking for something specific which is not in this list, please ask (https://fediversity.site/channel/streams).
## Fediverse FEPs
- ~~FEP-f1d5: Nodeinfo in FediverseSoftware~~ Take your trackers and MAUs and stick them where the sun don't shine.
- FEP-e232: Object links (aka quotedPosts)
- FEP-8b32: Object Integrity Proofs
- FEP-c390: Identity Proofs
- FEP-fb2a: Actor metadata
- FEP-612d: Identifying ActivityPub Objects through DNS
- FEP-2c59: Discovery of a Webfinger address from an ActivityPub actor
- FEP-61cf: The OpenWebAuth Protocol
Please see [Conversation Containers](https://fediversity.site/help/develop/en/Containers), which builds on the following 2 FEPs. The same mechanism may be used for groups.
- FEP-400e: Publicly-appendable ActivityPub collections
- FEP-7888: Demystifying the context property
Nomadic Identity: work in progress as of 29-May-2024 and is based on
- FEP-ef61: Portable Objects
- FEP-4adb: Dereferencing identifiers with webfinger
Planned support:
- FEP-d556: Server-Level Actor Discovery Using WebFinger
## C2S
This project supports ActivityPub C2S. You may authenticate with HTTP basic-auth, OAuth2, or OpenWebAuth. There is no media upload endpoint since the (deprecated) specification of that service has no workarounds for working in memory-restricted environments and most mobile phone photos exceed PHP's default upload size limits.
## Client search interface
Please see [Federated Search](https://fediversity.site/help/develop/en/Federated_Search)
If public access is allowed to the content search interface (a site security setting), clients may search the content of public messages or tags and are returned an ActivityStreams Collection of search results. When authenticated via OpenWebAuth, the search results may contain their own content or private content which they are permitted to access.
The URL endpoints for site search are:
@ -48,7 +72,9 @@ Direct Messages (DM) are differentiated from other private messaging using the n
## Events
Events and RSVP are supported per AS-vocabulary with the exception that a Create/Event is not transmitted. Invite/Event is the primary method of sharing events. For compatibility with some legacy applications, RSVP responses of Accept/Event, Reject/Event, TentativeAccept/Event and TentativeReject/Event are accepted as valid RSVP activities. By default, we send Accept/{Invite/Event} (and other RSVP responses) per AS-vocabulary. Events with no timezone (e.g. "all day events" or holidays) are sent with no 'Z' on the event times per RFC3339 Section 4.3. All event times are in UTC and timezone adjusted events are transmitted using Zulu time 'yyyy-mm-ddThh:mm:ssZ'. Event descriptions are sent using 'summary' and accepted using summary, name, and content in order of existence. These are converted internally to plaintext if they contain HTML. If 'location' contains coordinates, a map will typically be generated when rendered.
Events and RSVP are supported per AS-vocabulary with the exception that a Create/Event is not transmitted. Invite/Event is the primary method of sharing events. For compatibility with some legacy applications, RSVP responses of Accept/Event, Reject/Event, TentativeAccept/Event and TentativeReject/Event are accepted as valid RSVP activities. By default, we send Accept/{Invite/Event} (and other RSVP responses) per AS-vocabulary. Events with no timezone (e.g. "all day events" or holidays) are sent with no 'Z' on the event times per RFC3339 Section 4.3. All event times are in UTC and timezone adjusted events are transmitted using Zulu time 'yyyy-mm-ddThh:mm:ssZ'. Event descriptions are sent using 'summary' and accepted using summary, name, and content in order of existence. These are converted internally to plaintext if they contain HTML.
If 'location' contains coordinates, a map will typically be generated when rendered.
## Nomadic Identity
@ -59,39 +85,20 @@ The actor record for nomadic accounts contains a 'copiedTo' property which is ot
## Groups
Groups may be public or private. The initial thread starting post to a group is sent using a DM to the group and should be the only DM recipient. This helps preserve the sanctity of private groups and is a posting method available to most ActivityPub software, as opposed to bang tags (!groupname) which lack widespread support and normal @mentions which can create privacy issues and their associated drama. It will be converted to an embedded post authored by the group Actor (and attributed to the original Actor) and resent to all members. Followups and replies to group posts use normal federation methods. The actor type is 'Group' and can be followed using Follow/Group *or* Join/Group, and unfollowed by Undo/Follow *or* Leave/Group.
Groups may be public or private. The initial thread starting post to a group is sent using a DM to the group and should be the only DM recipient. This helps preserve the sanctity of private groups and is a posting method available to most ActivityPub software. Bang tags (!groupname) may also be used if supported. @mentions may be used for public groups (only). The initial post will be converted to an embedded post authored by the group Actor (and attributed to the original Actor) and resent to all members. In the future this will be provided as Add/Remove from the group collection -- see also [Conversation Containers](https://fediversity.site/help/develop/en/Containers). Followups and replies to group posts use normal federation methods.
Update: as of June 2021 comments to a group are sent via normal methods, but an additional Announce activity is now sent to ActivityPub connections so that the comments will be seen in the home timeline on microblog sites (Mastodon, etc.). Conversational or macroblog sites with working conversation view should filter/hide this redundant post.
The actor type is 'Group' and can be followed using Follow/Group *or* Join/Group, and unfollowed by Undo/Follow *or* Leave/Group. Other software will see both a Follow/Group activity and a Join/Group activity when somebody using this software joins a group. Consume whatever works for your software and ignore the other.
Update: as of 2021-04-08 @mentions are now permitted for posting to public and moderated groups but are not permitted for posting to restricted or private groups. The group owner can over-ride this behaviour as desired based on the group's security and privacy expectations. DMs (and wall-to-wall posts) are still the recommended methods for posting to groups because they can be used for any groups without needing to remember which are public and which are private; and which may have allowed or disallowed posting via mentions.
Update: as of 2021-04-30 We will support incoming group posts of the form Create/Note/Collection or Add/Note/Collection where the target Collection|orderedCollection is the group outbox or "wall". This should match the behaviour of the Smithereen project and is documented in Fediverse Enhancement Proposal FEP-400e. We also provide this structure automatically on outbound group posts if the actor record contains 'wall' (sm:wall); and add a mention tag in the activity to support group/relay implementations that only trigger on mentions.
Announce activities are sent alongside comments for the benefit of microblog projects.
## Comments
This project provides permission control and moderation of comments. By default comments are only accepted from existing connections. This can be changed by the individual. Other sites MAY use nomad:commentPolicy (string) as a guide if they do not wish to provide comment abilities where it is known in advance they will be rejected. A Reject/Note activity will be sent if the comment is not permitted. There is currently no response for moderated content, but will likely also be represented by Reject/Note.
This project provides permission control and moderation of comments. By default comments are only accepted from existing connections. This can be changed by the individual. The `canReply` field may be used as an indicator of general permission to comment by consuming software. This is an array of actors or collections which may be permitted to reply. If it is empty, replies will not be accepted. An `endDate` on a published Note (/Article/etc.) without a corresponding `startDate` indicates a time limit on replies. They will be rejected after that datetime.
'commentPolicy' can be any of
'authenticated' - matches the typical ActivityPub permissions
'contacts' - matches approved followers
'any connections' - matches followers regardless of approval
'site: foobar.com' - matches any actor or clone instance from 'foobar.com'
'public' - matches anybody at all, may require moderation if the network isn't known
'self' - matches the activity author only
'until=2001-01-01T00:00Z' - comments are closed after the date given. This can be supplied on its own or appended to any other commentPolicy string by preceding with a space; for example 'contacts until=2001-01-01T00:00Z'.
The 'canReply' field may also be used for comment control. This contains either an actor id, or an array of actor ids; which may include groups or other actor collections such as access lists.
## Expiring content
Activity objects may include an 'expires' field; after which time they are removed. The removal occurs with a federated Delete, but this is a best faith effort. We automatically delete any local objects we receive with an 'exires' field after it expires regardless of whether or not we receive a Delete activity. The expiration is specified as an ISO8601 date/time.
Activity objects may include an 'expires' field; after which time they are removed. The removal occurs with a federated Delete, but this is a best faith effort. We automatically delete any local objects we receive with an 'expires' field after it expires regardless of whether we receive a Delete activity. The expiration is specified as an ISO8601 date/time.
## Private Media
@ -100,12 +107,12 @@ Private media MAY be accessed using OCAP or OpenWebAuth. Bearcaps are supported
## Permission System
The Nomad permission system has years of historical use and is different than and the reverse of the typical ActivityPub project. We consider 'Follow' to be an anti-pattern which encourages pseudo anonymous stalking. A Follow activity by an actor on this project typically means the actor on this project will send activities to the recipient. It may also confer other permissions. Accept/Follow usually provides permission to receive content from the referenced actor, depending on their privacy settings.
The Nomad permission system has years of historical use and is different than the typical ActivityPub project. A Follow activity by an actor on this project typically means the actor on this project has changed the permissions associated with the followee. This could one of 15-30 different access controls and does not by itself indicate a follower relationship. It could provide permission for the target actor to upload to file storage for example. Future work will make the precise permission set available for access over ActivityPub to consuming applications. This is currently in progress as of 29-May-2024.
## Delivery model
This project uses the relay system pioneered by projects such as Friendica, Diaspora, and Hubzilla which attempts to keep entire conversations intact and keeps the conversation initiator in control of the privacy distribution. This is not guaranteed under ActivityPub where conversation members can cc: others who were not in the initial privacy group. We encourage projects to not allow additional recipients or not include their own followers in followups. Followups SHOULD have one recipient - the conversation owner or originator, and are relayed by the owner to the other conversation members. This normally requires the use of LD-Signatures but may also be accessible through authenticated fetch of the activity using HTTP signatures.
See [Conversation Containers](https://fediversity.site/help/develop/en/Containers)
## Content
@ -113,7 +120,7 @@ Content may be rich multi-media and renders nicely as HTML. Multicode is used an
Mastodon 'summary' does not invoke any special handling so 'summary' can be used for its intended purpose as a content summary. Mastodon 'sensitive' is honoured and results in invoking whatever mechanisms the user has selected to deal with this type of content. By default images are obscured and are 'click to view'. Sensitive text is not treated specially, but may be obscured using the NSFW plugin or filtered per connection based on string match, tags, patterns, languages, or other criteria.
Mastodon "custom emojis" are supported for post content, but **not** in display names, which are restricted to UTF-8.
## Edits
@ -123,11 +130,10 @@ Edited posts and comments are sent with Update/Note and an 'updated' timestamp a
Announce and relay activities use two mechanisms. As well as the Announce activity, a new message is generated with an embedded rendering of the shared content as the message content. This message may (should) contain additional commentary in order to comply with the Fair Use provisions of copyright law. The other reason is our use of comment permissions. Comments to Announce activities are sent to the author (who typically accepts comments only from connections). Comment to embedded forwards are sent to the sender. This difference in behaviour allows groups to work correctly in the presence of comment permissions.
Discussion (2021-04-17): In the email world this type of conflict is resolved by the use of the reply-to header (e.g. in this case reply to the group rather than to the author) as well as the concept of a 'sender' which is different than 'from' (the author). We will soon be modelling the first one in ActivityPub with the use of 'replyTo'. If you see 'replyTo' in an activity it indicates that replies SHOULD go to that address rather than the author's inbox. We will implement this first and come up with a proposal for 'sender' if this gets any traction. If enough projects support these constructs we can eliminate the multiple relay mechanisms and in the process make ActivityPub much more versatile when it comes to organisational and group communications. Our primary use case for 'sender' is to provide an ActivityPub origin to a message that was imported from another system entirely (such as Diaspora or from RSS source). In this case we would set 'attributedTo' to the remote identity that authored the content, and 'sender' to the person that posted it in ActivityPub.
## Emoji Reactions
We consider a reply message containing exactly one emoji and no other text or markup to be an emoji reaction. We indicate this state internally on receipt but do nothing to identify it specifically to downstream recipients.
We consider a reply message containing exactly one emoji and no other text or markup to be an emoji reaction. We indicate this state internally on receipt but currently do nothing to identify it specifically to downstream recipients.
## Mastodon Custom Emojis

View file

@ -16,7 +16,7 @@ If you wish to include the special characters ( \* or \_ ) without interpreting
[tr][td][nomd] __bold text__ [/nomd][/td][td] __bold text__ [/td][/tr]
[tr][td][nomd] ***bold and italic text*** [/nomd][/td][td] ***bold and italic text*** [/td][/tr]
[tr][td][nomd] ___bold and italic text___ [/nomd][/td][td] ___bold and italic text___ [/td][/tr]
[tr][td][nomd] ~~strike text~~ [/nomd][/td][td] ~~strike text~~ [/td][/tr]
[/table]
[h3]Headers[/h3]
@ -93,8 +93,6 @@ This is an example of `inline code`.
[h3]Lists[/h3]
In order to reduce "false positives", markdown lists are only rendered if they contain more than one list element within the entire content body.
As with bold and italic, the first character of an unordered list may be preceded by a backslash or wrapped in [nobb][nomd][/nomd][/nobb] tags to prevent normal text lines beginning with these characters from being interpreted as a list.

View file

@ -1325,6 +1325,11 @@ function md_italic($content)
return '<em>' . $content[1] . $content[3] . '</em>';
}
function md_del($content)
{
return '<del>' . $content[1] . $content[3] . '</del>';
}
function md_bold($content)
{
@ -2179,9 +2184,11 @@ function bbcode($Text, $options = [])
$Text = preg_replace_callback('#(^|\n| )(?<!\\\)([*_]{3})([^\n]+?)\2#', 'md_bolditalic', $Text);
$Text = preg_replace_callback('#(^|\n| )(?<!\\\)([*_]{2})([^\n]+?)\2#', 'md_bold', $Text);
$Text = preg_replace_callback('#(^|\n| )(?<!\\\)([*_])([^\n|`]+?)\2#m', 'md_italic', $Text);
$Text = preg_replace_callback('#(^|\n| )(?<!\\\)([~]{2})([^\n]+?)\2#', 'md_del', $Text);
// strip the backslash from escaped bold/italic markdown sequences
// strip the backslash from escaped bold/italic/del markdown sequences
$Text = preg_replace('#(\\\)([*_])#', '$2', $Text);
$Text = preg_replace('#(\\\)([~])#', '$2', $Text);
$Text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx', 'md_topheader', $Text);
$Text = preg_replace_callback('#^(\#{1,6})\s+([^\#]+?)\s*\#*$#m', 'md_header', $Text);
@ -2209,11 +2216,11 @@ function bbcode($Text, $options = [])
// unordered lists
$matches = [];
// Ignore if there is only one list element as it could be a false positive.
if (preg_match_all('#^(?<!\\\)[*\-+] +(.*?)$#m', $Text, $matches, PREG_SET_ORDER) && count($matches) > 1) {
// if (preg_match_all('#^(?<!\\\)[*\-+] +(.*?)$#m', $Text, $matches, PREG_SET_ORDER) && count($matches) > 1) {
$Text = preg_replace('#^(?<!\\\)[*\-+] +(.*?)$#m', '<ul><li>$1</li></ul>', $Text);
// strip the backslash escape if present
$Text = preg_replace('#^(\\\)([*\-+]) #m', '$2', $Text);
}
// }
// order lists
$Text = preg_replace('#^(?<!\\\)(\d+[\.\)]) +(.*?)$#m', '<ol><li value="$1">$2</li></ol>', $Text);
$Text = preg_replace('#^(\\\)(\d+[\.\)])#m', '$2', $Text);

View file

@ -84,6 +84,7 @@ class Notifier implements DaemonInterface
public static $deliveries = [];
public static $recipients = [];
public static $env_recips = [];
public static $postopts = [];
public static $packet_type = 'activity';
public static $encoding = 'activitystreams';
public static $encoded_item = null;
@ -363,6 +364,13 @@ class Notifier implements DaemonInterface
$thread_is_public = !intval($parent_item['item_private']);
$question = $parent_item['verb'] === 'Question';
}
$thread_parent = q("select * from item where mid = '%s' and uid = %d limit 1",
dbesc($target_item['thr_parent']),
intval($target_item['uid'])
);
if ($thread_parent) {
$thread_parent = array_shift($thread_parent);
}
// avoid looping of discover items 12/4/2014
@ -412,6 +420,8 @@ class Notifier implements DaemonInterface
self::$packet_type = 'response';
}
self::$postopts = explode(',', $target_item['postopts']);
if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
logger('followup relay (upstream delivery)', LOGGER_DEBUG);
$sendto = ($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan'];
@ -438,6 +448,11 @@ class Notifier implements DaemonInterface
self::$recipients = $sendto;
}
}
if (in_array('sender', self::$postopts)) {
$sendto = [$thread_parent['author_xchan']];
}
logger('replyto: upstream recipients ' . print_r($sendto, true), LOGGER_DEBUG);
self::$private = true;

View file

@ -5162,7 +5162,6 @@ class Activity
'https://www.w3.org/ns/did/v1',
'https://w3id.org/security/multikey/v1',
'https://w3id.org/security/data-integrity/v1',
'https://purl.archive.org/socialweb/webfinger',
self::ap_schema($contextType)
]];
}
@ -5178,7 +5177,13 @@ class Activity
'@type' => '@id',
'@container' => '@list'
],
'nomad' => 'https://purl.org/nomad#',
'wf' => 'https://purl.archive.org/socialweb/webfinger',
'xsd' => 'http://www.w3.org/2001/XMLSchema#',
'webfinger' => [
'@id' => 'wf:webfinger',
'@type' => 'xsd:string'
],
'nomad' => z_root() . '/apschema#',
'toot' => 'http://joinmastodon.org/ns#',
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'oauthRegistrationEndpoint' => 'nomad:oauthRegistrationEndpoint',

View file

@ -135,7 +135,7 @@ class ThreadItem
if ($item['item_restrict'] & 1) {
$privacy_warning = true;
$lock = t('This comment was sent as a direct (private) message but the conversation has a different privacy expectation and any replies to it may be seen by others. Discretion advised.');
$lock = t('This comment was sent as a protected or private message but the conversation has a different privacy expectation and any replies to it may be seen by others. Discretion advised.');
}
@ -961,7 +961,15 @@ class ThreadItem
$feature_auto_save_draft = ((Features::enabled($conv->get_profile_owner(), 'auto_save_draft')) ? "true" : "false");
$permanent_draft = ((intval($conv->get_profile_owner()) === intval(local_channel()) && Apps::system_app_installed($conv->get_profile_owner(), 'Drafts')) ? t('Save draft') : EMPTY_STR);
/*
$isContained = str_contains($parent_item['tgt_type'], 'Collection') || ($parent_item['item_restrict'] & 4);
$is_moderated = their_perms_contains($parent_item['uid'], (is_array($sendto) ? $sendto[0] : $sendto), 'moderated');
if ($relay_to_owner && $thread_is_public && (! $is_moderated) && (! $question) && (! Channel::is_group($parent_item['uid']))) {
if (get_pconfig($target_item['uid'], 'system', 'hyperdrive', true) || !$isContained) {
//
}
}
*/
$comment_box = replace_macros($template, [
'$return_path' => '',
@ -988,7 +996,6 @@ class ThreadItem
'$edupload' => t('Attach file from your device'),
'$edembed' => t('Attach file from your personal cloud'),
'$edurl' => t('Insert Link'),
'$edvideo' => t('Video'),
'$preview' => t('Preview'),
'$reset' => t('Reset'),
'$indent' => $indent,

View file

@ -855,7 +855,7 @@ class Item extends Controller
$item_blocked = $orig_post['item_blocked'];
$postopts = $orig_post['postopts'];
$postopts = explode(',', $orig_post['postopts']);
$created = ((intval($orig_post['item_unpublished'])) ? $created : $orig_post['created']);
$expires = ((intval($orig_post['item_unpublished'])) ? NULL_DATE : $orig_post['expires']);
$mid = $orig_post['mid'];
@ -886,16 +886,22 @@ class Item extends Controller
$location = ((isset($_REQUEST['location'])) ? notags(trim($_REQUEST['location'])) : EMPTY_STR);
$lat = ((isset($_REQUEST['lat'])) ? floatval($_REQUEST['lat']) : 0.0);
$lon = ((isset($_REQUEST['lon'])) ? floatval($_REQUEST['lon']) : 0.0);
$audience = ((isset($_REQUEST['audience'])) ? notags(trim($_REQUEST['audience'])) : EMPTY_STR);
$verb = ((isset($_REQUEST['verb'])) ? notags(trim($_REQUEST['verb'])) : EMPTY_STR);
$title = ((isset($_REQUEST['title'])) ? escape_tags(trim($_REQUEST['title'])) : EMPTY_STR);
$summary = ((isset($_REQUEST['summary'])) ? trim($_REQUEST['summary']) : EMPTY_STR);
$body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : EMPTY_STR);
$body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : EMPTY_STR);
$postopts = '';
$postopts = [];
$haslocation = $lat || $lon;
$allow_empty = ((($checkin || $checkout) && $haslocation) || $_REQUEST['allow_empty']);
$private = ((isset($private) && $private) ? $private : intval($acl->is_private() || ($public_policy)));
// preferred audience for replies
if ($audience && in_array($audience, ['sender', 'conversation', 'followers'])) {
$postopts[] = $audience;
}
// Normalise the line endings on multi-line fields.
$summary = str_replace("\r\n", "\n", $summary);
$body = str_replace("\r\n", "\n", $body);
@ -1478,7 +1484,7 @@ class Item extends Controller
$datarray['deny_gid'] = $str_group_deny;
$datarray['attach'] = $attachments;
$datarray['thr_parent'] = $thr_parent;
$datarray['postopts'] = $postopts;
$datarray['postopts'] = implode(',', $postopts);
$datarray['item_wall'] = intval($item_wall);
$datarray['item_origin'] = intval($item_origin);
$datarray['item_type'] = $webpage;

File diff suppressed because it is too large Load diff

View file

@ -1,2 +1,2 @@
<?php
define ('STD_VERSION', '24.05.25');
define ('STD_VERSION', '24.05.27');

View file

@ -62,9 +62,6 @@
<button type="button" class="btn btn-outline-secondary btn-sm" title="{{$edurl}}" onclick="insertbbcomment('none','url', 'desc');">
<i class="fa fa-link comment-icon"></i>
</button>
<button type="button" class="btn btn-outline-secondary btn-sm" title="{{$edvideo}}" onclick="insertbbcomment('none','video', 'desc');">
<i class="fa fa-video-camera comment-icon"></i>
</button>
</div>
</div>
</div>