From 434c407d6f55075a4f6c5b33c1f79a05c989185c Mon Sep 17 00:00:00 2001 From: nobody Date: Mon, 26 Apr 2021 21:32:37 -0700 Subject: [PATCH 1/4] add uploaded photos as attachments as well as inline --- Zotlabs/Lib/Activity.php | 8 ++++---- doc/en/apps.mc | 32 ++++++++++++++++++-------------- include/event.php | 3 ++- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 566992300..17e5620ee 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2854,7 +2854,7 @@ class Activity { $ptr = [ $act->obj['url'] ]; } foreach ($ptr as $vurl) { - if (in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'],$s['body'])) { + if (isset($vurl['mediaType']) && in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'],$s['body'])) { $s['body'] .= "\n\n" . '[audio]' . $vurl['href'] . '[/audio]'; break; } @@ -2886,7 +2886,7 @@ class Activity { $ptr = [ $act->obj['url'] ]; } foreach ($ptr as $vurl) { - if (strpos($s['body'],$vurl['href']) === false) { + if (is_array($vurl) && isset($vurl['href']) && strpos($s['body'],$vurl['href']) === false) { $s['body'] .= "\n\n" . '[zmg]' . $vurl['href'] . '[/zmg]'; break; } @@ -2915,7 +2915,7 @@ class Activity { $ptr = [ $act->obj['url'] ]; } foreach ($ptr as $vurl) { - if (array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { + if (is_array($vurl) && array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { $purl = $vurl['href']; break; } @@ -2955,7 +2955,7 @@ class Activity { $ptr = [ $act->obj['url'] ]; } foreach ($ptr as $vurl) { - if (array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { + if (is_array($vurl) && array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { $s['plink'] = $vurl['href']; break; } diff --git a/doc/en/apps.mc b/doc/en/apps.mc index 37189adb8..231dd96c3 100644 --- a/doc/en/apps.mc +++ b/doc/en/apps.mc @@ -3,7 +3,7 @@ Available apps ### Calendar -This app provides access to a local CalDAV server which can be used to sync/manage calendars from your operating system or email program. It is not the same as the Events app and should only be installed if you have a specific need for CalDAV. +This app provides access to a local CalDAV server which can be used to sync/manage calendars from your operating system or email program. It is not the same as the Events app and should only be installed if you have a specific need for a CalDAV server. ### Categories @@ -15,7 +15,7 @@ Installed by default. This app provides access to your channel home page. ### Clients -This app allows you to create Oauth2/Openid access credentials. Typically used to provide authentication for mobile and third-party client applications. +This app allows you to create and manage Oauth2 access credentials, which are typically used to provide authentication for mobile and third-party client applications. ### Comment Control @@ -27,11 +27,11 @@ Installed by default. This app manages your connections (followers and following ### Content Filter -Allows you to specify different rules to incoming posts and comments, either on a per connection basis or as a global filter which applies to all incoming messages. Filtering can take place using hashtags, categories, regular expressions, text content, and language matching. +Allows you to specify different rules to incoming posts and comments, either on a per connection basis or as a global filter which applies to all incoming messages. Filtering can take place using hashtags, categories, regular expressions, text content, and language matching. Posts and comments matching the rules are rejected and will not be stored. ### Content Import -Requires the 'content_import' addon. When migrating to a new site, first import the identity and settings. Then install/run this app to import your content - such as posts, comments, files, and photos. +Requires the site administrator to install the 'content_import' addon. This allows you to migrate content from another instance of this channel. It should not be needed unless there were issues importing content and/or file storage when the channel was first imported. ### Directory @@ -57,7 +57,7 @@ Installed by default. This app provides access to your cloud storage and WebDAV ### Followlist -This app is only present if the 'followlist' addon is installed. It allows you to bulk connect with a list of channels. Typically this will be the 'following' ActivityPub collection on another server. We also accept Mastodon contact export files. +This app is only present if the 'followlist' addon is installed by the site administrator. It allows you to bulk connect with a list of channels. Typically this will be the 'following' ActivityPub collection on another server. We also accept Mastodon contact export files. ### Friend Zoom @@ -69,7 +69,7 @@ Set a post to be published at/after a certain date/time. Usually used for automa ### Gallery -Requires the 'gallery' addon. This provides an improved image browser to your photos than the stock 'Photos' app. Interactions with photos in your stream are modified slightly. +Available if the 'gallery' addon has been installed by the site administrator. This provides an improved image browser to your photos than the stock 'Photos' app. Interactions with photos in your stream are modified slightly. ### Guest Pass @@ -77,7 +77,7 @@ Does not require app installation, although it will be more accessible if the ap ### Hexit -Requires the 'hexit' addon. This provides an online hexadecimal/decimal converter. +Available if the 'hexit' addon has been installed by the site administrator. This provides an online hexadecimal/decimal converter. ### Language @@ -89,7 +89,7 @@ Installed by default. Some software refers to this functionality as 'Aspects' (D ### Markup -Provides editor buttons for bold, italic, underline, etc. Otherwise the relevant codes will need to be entered manually. This software recognises both Markdown and bbcode. +Provides editor buttons for bold, italic, underline, etc. Otherwise the relevant codes will need to be entered manually. This software recognises Markdown, HTML, and bbcode. ### Notes @@ -97,11 +97,15 @@ Provides a simple notepad on your stream page for making notes and reminders. ### NSFW -"Not Safe For Work". Requires the 'nsfw' addon. By default this will collapse and hide posts matching any of your rules unless you are running in "safe mode". These rules are based on hashtags, text content, regular expressions, and language. It is like the 'Content Filter' app except that all matching posts are present in your stream but require you to open each such message to view. Posts matching 'Content Filter' rules are rejected and will not be present in your stream. You can select whether or not you are running in 'safe mode' in your personal menu, and this setting is preserved separately for each login. This means your work computer can be in 'safe mode' and questionable content hidden, while your home computer may be configured to show everything by default. +"Not Safe For Work". Available if the 'nsfw' addon has been installed on this site. By default this will collapse and hide posts matching any of your rules unless you are running in "safe mode". These rules are based on hashtags, text content, regular expressions, and language. + +It is like the 'Content Filter' app except that all matching posts are present in your stream but require you to open each such message to view. Posts matching 'Content Filter' rules are rejected and will not be present in your stream. + +You can select whether or not you are running in 'safe mode' in your personal menu, and this setting is preserved separately for each login. This means your work computer can be in 'safe mode' and questionable content hidden, while your home computer may be configured to show everything by default. ### Photomap -If your uploaded photos have location support, this addon provides an optional map display of those locations in your 'Photos' app. This may require installing either the 'openstreetmap' addon or some other map provider. +If your uploaded photos have location support, this addon provides an optional map display of those locations in your 'Photos' app. This may require the site administrator to install a map provider addon such as 'openstreetmap'. ### Photos @@ -113,11 +117,11 @@ This app lets you open a post editor at any time. ### Qrator -Requires the 'qrator' addon and provides a page to generate QR codes for your requirements. +Available if the 'qrator' addon has been installed. This provides a page to generate QR codes for your requirements. ### Rainbow Tag -Requires both the 'rainbowtag' addon and Tagadelic app. This converts the tag clouds provided by Tagadelic from monochrome into color. +Available if the 'rainbowtag' addon has been installed on the site. Also requires the Tagadelic app. This converts the tag clouds provided by Tagadelic from monochrome into color. ### Search @@ -142,7 +146,7 @@ Installed by default. This represents the conversations of you and your connecti ### Stream Order -Requires the 'stream_order' addon. Provides a setting on the Stream page to select between various sort orders, such as 'last commented date' (conversational), 'posted date' (also conversational) and 'date unthreaded' which lists every activity as a separate message. +Available if the 'stream_order' addon is installed on the site. Provides a setting on the Stream page to select between various sort orders, such as 'last commented date' (conversational), 'posted date' (also conversational) and 'date unthreaded' which lists every activity as a separate message. ### Suggest Channels @@ -163,7 +167,7 @@ This is like 'Lists', except you do not need to manage the list membership. By d ### Zotpost -Requires the 'zotpost' addon. This configures the zotpost addon to automatically cross-post to your channel on another Zot6 site. +Available if the 'zotpost' addon has been installed on the site. This configures the zotpost addon to automatically cross-post to your channel on another Zot6 site. diff --git a/include/event.php b/include/event.php index d71407fc4..71722aa87 100644 --- a/include/event.php +++ b/include/event.php @@ -7,6 +7,7 @@ use Sabre\VObject; use Zotlabs\Lib\Libsync; use Zotlabs\Lib\Activity; +use Zotlabs\Access\AccessControl; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; @@ -610,7 +611,7 @@ function event_addtocal($item_id, $uid) { if($ev['private']) $ev['allow_cid'] = '<' . $channel['channel_hash'] . '>'; else { - $acl = new Zotlabs\Access\AccessControl($channel); + $acl = new AccessControl($channel); $x = $acl->get(); $ev['allow_cid'] = $x['allow_cid']; $ev['allow_gid'] = $x['allow_gid']; From 34c08f36e629752b1bda31b53fd6ac8dc30be9c1 Mon Sep 17 00:00:00 2001 From: nobody Date: Tue, 27 Apr 2021 13:40:27 -0700 Subject: [PATCH 2/4] more logging of copy_of_pubitem to find issue --- include/items.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/items.php b/include/items.php index a0684bc4f..f99225943 100644 --- a/include/items.php +++ b/include/items.php @@ -4771,7 +4771,7 @@ function copy_of_pubitem($channel,$mid) { $result = null; $syschan = get_sys_channel(); - // logger('copy_of_pubitem: ' . $channel['channel_id'] . ' mid: ' . $mid); + logger('copy_of_pubitem: ' . $channel['channel_id'] . ' mid: ' . $mid); $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($mid), @@ -4798,6 +4798,7 @@ function copy_of_pubitem($channel,$mid) { intval($channel['channel_id']) ); if ($d) { + logger('mid: ' . $mid . ' already copied. Continuing.'); continue; } @@ -4815,5 +4816,8 @@ function copy_of_pubitem($channel,$mid) { } } + else { + logger('copy query failed.'); + } return $result; } From 42943ab824fe41755ca43b124576ddd828ea5534 Mon Sep 17 00:00:00 2001 From: nobody Date: Tue, 27 Apr 2021 17:18:18 -0700 Subject: [PATCH 3/4] more work on copy_of_pubitem issues --- Zotlabs/Lib/Libzotdir.php | 7 ++ Zotlabs/Module/Item.php | 3 +- Zotlabs/Module/Like.php | 7 +- Zotlabs/Module/Outbox.php | 138 +++++++++++++++++++++++++++++++++-- Zotlabs/Module/React.php | 9 ++- Zotlabs/Module/Subthread.php | 7 ++ Zotlabs/Module/Tagger.php | 7 +- include/items.php | 14 +++- 8 files changed, 175 insertions(+), 17 deletions(-) diff --git a/Zotlabs/Lib/Libzotdir.php b/Zotlabs/Lib/Libzotdir.php index b06db6321..6acbaba8c 100644 --- a/Zotlabs/Lib/Libzotdir.php +++ b/Zotlabs/Lib/Libzotdir.php @@ -268,6 +268,13 @@ class Libzotdir { if (! $hash) return false; + + $maxlen = get_max_import_size(); + + if($maxlen && mb_strlen($profile['about']) > $maxlen) { + $profile['about'] = mb_substr($profile['about'],0,$maxlen,'UTF-8'); + } + $arr = []; $arr['xprof_hash'] = $hash; diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index be3d1f66c..415b13474 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -491,6 +491,7 @@ class Item extends Controller { intval($uid) ); } + // if this isn't the real parent of the conversation, find it if ($r) { $parid = $r[0]['parent']; @@ -504,7 +505,7 @@ class Item extends Controller { // if interacting with a pubstream item (owned by the sys channel), // create a copy of the parent in your stream - if ($r[0]['uid'] === $sys['channel_id'] && local_channel()) { + if (local_channel()) { $r = [ copy_of_pubitem(App::get_channel(), $r[0]['mid']) ]; } } diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php index 042d1d8db..ca480c552 100644 --- a/Zotlabs/Module/Like.php +++ b/Zotlabs/Module/Like.php @@ -238,11 +238,10 @@ class Like extends Controller { ); // if interacting with a pubstream item, - // create a copy of the parent in your stream. If not the conversation - // parent, copy that as well. + // create a copy of the parent in your stream. - if($r) { - if($r[0]['uid'] === $sys_channel['channel_id'] && local_channel()) { + if ($r) { + if (local_channel()) { $r = [ copy_of_pubitem(App::get_channel(), $r[0]['mid']) ]; } } diff --git a/Zotlabs/Module/Outbox.php b/Zotlabs/Module/Outbox.php index fb2121a07..7c91e0399 100644 --- a/Zotlabs/Module/Outbox.php +++ b/Zotlabs/Module/Outbox.php @@ -9,6 +9,7 @@ use Zotlabs\Lib\LDSignatures; use Zotlabs\Lib\ThreadListener; use Zotlabs\Web\HTTPSig; use Zotlabs\Lib\Activity; +use Zotlabs\Lib\ActivityPub; use Zotlabs\Lib\Config; /** @@ -18,11 +19,6 @@ use Zotlabs\Lib\Config; class Outbox extends Controller { - function init() { - - - } - function post() { if (argc() < 2) { killme(); @@ -45,7 +41,17 @@ class Outbox extends Controller { if (! $observer) { killme(); } - + + if ($observer['xchan_hash'] !== $channel['channel_hash']) { + if (! perm_is_allowed($channel['channel_id'],$observer['xchan_hash'],'post_wall')) { + logger('outbox post permission denied to ' . $observer['xchan_name']); + killme(); + } + } +// disable C2S until we've fully tested it. +return; + + $data = file_get_contents('php://input'); if (! $data) { return; @@ -59,15 +65,131 @@ class Outbox extends Controller { return; } + if (! PConfig::Get($channel['channel_id'],'system','activitypub',Config::Get('system','activitypub',ACTIVITYPUB_ENABLED))) { + return; + } + + logger('outbox_channel: ' . $channel['channel_address'],LOGGER_DEBUG); +// switch ($AS->type) { +// case 'Follow': +// if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStreams::is_an_actor($AS->obj['type']) && isset($AS->obj['id'])) { +// // do follow activity +// Activity::follow($channel,$AS); +// } +// break; +// case 'Invite': +// if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { +// // do follow activity +// Activity::follow($channel,$AS); +// } +// break; +// case 'Join': +// if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { +// // do follow activity +// Activity::follow($channel,$AS); +// } +// break; +// case 'Accept': +// // Activitypub for wordpress sends lowercase 'follow' on accept. +// // https://github.com/pfefferle/wordpress-activitypub/issues/97 +// // Mobilizon sends Accept/"Member" (not in vocabulary) in response to Join/Group +// if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && in_array($AS->obj['type'], ['Follow','follow', 'Member'])) { +// // do follow activity +// Activity::follow($channel,$AS); +// } +// break; +// case 'Reject': +// default: +// break; +// +// } + // These activities require permissions + $item = null; + switch ($AS->type) { + case 'Update': + if (is_array($AS->obj) && array_key_exists('type',$AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { + // pretend this is an old cache entry to force an update of all the actor details + $AS->obj['cached'] = true; + $AS->obj['updated'] = datetime_convert('UTC','UTC','1980-01-01', ATOM_TIME); + Activity::actor_store($AS->obj['id'],$AS->obj); + break; + } + case 'Accept': + if (is_array($AS->obj) && array_key_exists('type',$AS->obj) && (ActivityStreams::is_an_actor($AS->obj['type']) || $AS->obj['type'] === 'Member')) { + break; + } + case 'Create': + case 'Like': + case 'Dislike': + case 'Announce': + case 'Reject': + case 'TentativeAccept': + case 'TentativeReject': + case 'Add': + case 'Arrive': + case 'Block': + case 'Flag': + case 'Ignore': + case 'Invite': + case 'Listen': + case 'Move': + case 'Offer': + case 'Question': + case 'Read': + case 'Travel': + case 'View': + case 'emojiReaction': + case 'EmojiReaction': + case 'EmojiReact': + // These require a resolvable object structure + if (is_array($AS->obj)) { + // The boolean flag enables html cache of the item + $item = Activity::decode_note($AS,true); + } + else { + logger('unresolved object: ' . print_r($AS->obj,true)); + } + break; + case 'Undo': + if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Follow') { + // do unfollow activity + Activity::unfollow($channel,$AS); + break; + } + case 'Leave': + if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { + // do unfollow activity + Activity::unfollow($channel,$AS); + break; + } + case 'Tombstone': + case 'Delete': + Activity::drop($channel,$observer_hash,$AS); + break; + case 'Move': + if($observer_hash && $observer_hash === $AS->actor + && is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStream::is_an_actor($AS->obj['type']) + && is_array($AS->tgt) && array_key_exists('type', $AS->tgt) && ActivityStream::is_an_actor($AS->tgt['type'])) { + ActivityPub::move($AS->obj,$AS->tgt); + } + break; + case 'Add': + case 'Remove': + default: + break; + } + if ($item) { + logger('parsed_item: ' . print_r($item,true),LOGGER_DATA); + Activity::store($channel,$observer_hash,$AS,$item); + } - - + http_status_exit(200,'OK'); return; } diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php index 1607d8078..b3c806941 100644 --- a/Zotlabs/Module/React.php +++ b/Zotlabs/Module/React.php @@ -34,11 +34,18 @@ class React extends Controller { ); if(! $i) { + // try the global public stream $i = q("select * from item where id = %d and uid = %d", intval($postid), intval($sys['channel_id']) ); - + // try the local public stream + if (! $i) { + $i = q("select * from item where id = %d and item_wall = 1 and item_private = 0", + intval($postid) + ); + } + if($i) { $i = [ copy_of_pubitem($channel, $i[0]['mid']) ]; $postid = (($i) ? $i[0]['id'] : 0); diff --git a/Zotlabs/Module/Subthread.php b/Zotlabs/Module/Subthread.php index 565eafed2..4a9afcec3 100644 --- a/Zotlabs/Module/Subthread.php +++ b/Zotlabs/Module/Subthread.php @@ -36,10 +36,17 @@ class Subthread extends Controller { ); if (! $i) { + // try the global public stream $i = q("select * from item where id = %d and uid = %d", intval($postid), intval($sys['channel_id']) ); + // try the local public stream + if (! $i) { + $i = q("select * from item where id = %d and item_wall = 1 and item_private = 0", + intval($postid) + ); + } if ($i) { $i = [ copy_of_pubitem($channel, $i[0]['mid']) ]; diff --git a/Zotlabs/Module/Tagger.php b/Zotlabs/Module/Tagger.php index be91335ea..33280772f 100644 --- a/Zotlabs/Module/Tagger.php +++ b/Zotlabs/Module/Tagger.php @@ -40,7 +40,12 @@ class Tagger extends \Zotlabs\Web\Controller { intval($item_id), intval($sys['channel_id']) ); - if($r) { + if (! $r) { + $r = q("select * from item where id = %d and item_private = 0 and item_wall = 1", + intval($item_id) + ); + } + if ($r) { $r = [ copy_of_pubitem($channel, $i[0]['mid']) ]; $item_id = (($r) ? $r[0]['id'] : 0); } diff --git a/include/items.php b/include/items.php index f99225943..445d59b07 100644 --- a/include/items.php +++ b/include/items.php @@ -4784,11 +4784,21 @@ function copy_of_pubitem($channel,$mid) { return $item[0]; } - + // this query is used for the global public stream $r = q("select * from item where parent_mid = ( select parent_mid from item where mid = '%s' and uid = %d ) order by id ", dbesc($mid), intval($syschan['channel_id']) ); + + // if that failed, try to find entries that would have been posted in the local public stream + if (! $r) { + $r = q("select * from item where parent_mid = ( select distinct (parent_mid) from item where mid = '%s' and item_wall = 1 and item_private = 0 ) order by id ", + dbesc($mid), + intval($syschan['channel_id']) + ); + } + + if ($r) { $items = fetch_post_tags($r,true); @@ -4798,7 +4808,7 @@ function copy_of_pubitem($channel,$mid) { intval($channel['channel_id']) ); if ($d) { - logger('mid: ' . $mid . ' already copied. Continuing.'); + logger('mid: ' . $rv['mid'] . ' already copied. Continuing.'); continue; } From 90e8b47077873de95a0591503e2282968e93d404 Mon Sep 17 00:00:00 2001 From: nobody Date: Tue, 27 Apr 2021 20:16:54 -0700 Subject: [PATCH 4/4] revision --- boot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot.php b/boot.php index 834ab25a3..b6975be8c 100755 --- a/boot.php +++ b/boot.php @@ -16,7 +16,7 @@ use Zotlabs\Daemon\Run; * @brief This file defines some global constants and includes the central App class. */ -define ( 'STD_VERSION', '21.04.21' ); +define ( 'STD_VERSION', '21.04.28' ); define ( 'ZOT_REVISION', '10.0' ); define ( 'DB_UPDATE_VERSION', 1248 );