diff options
-rw-r--r-- | Zotlabs/Lib/Activity.php | 183 | ||||
-rw-r--r-- | Zotlabs/Lib/Libzot.php | 115 |
2 files changed, 43 insertions, 255 deletions
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index f10a2bace..90d7af8e8 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -8,7 +8,6 @@ use Zotlabs\Access\PermissionRoles; use Zotlabs\Access\Permissions; use Zotlabs\Daemon\Master; use Zotlabs\Web\HTTPSig; -use Zotlabs\Entity\Item; require_once('include/event.php'); require_once('include/html2plain.php'); @@ -571,25 +570,6 @@ class Activity { if ($i['mid'] !== $i['parent_mid']) { $ret['inReplyTo'] = ((strpos($i['thr_parent'], 'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent'])); - - $cnv = IConfig::Get($i['parent'], 'activitypub', 'context'); - if (!$cnv) { - $cnv = $i['parent_mid']; - } - } - - if (empty($cnv)) { - $cnv = IConfig::Get($i, 'activitypub', 'context'); - if (!$cnv) { - $cnv = $i['parent_mid']; - } - } - - if (!empty($cnv)) { - if (is_string($cnv) && str_starts_with($cnv, z_root())) { - $cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv); - } - $ret['context'] = $cnv; } if ($i['mimetype'] === 'text/bbcode') { @@ -609,12 +589,6 @@ class Activity { $t = self::encode_taxonomy($i); if ($t) { - foreach($t as $tag) { - if (strcasecmp($tag['name'], '#nsfw') === 0 || strcasecmp($tag['name'], '#sensitive') === 0) { - $ret['sensitive'] = true; - } - } - $ret['tag'] = $t; } @@ -622,20 +596,7 @@ class Activity { if ($a) { $ret['attachment'] = $a; } -/* - if ($i['target']) { - if (is_string($i['target'])) { - $tmp = json_decode($i['target'], true); - if ($tmp !== null) { - $i['target'] = $tmp; - } - } - $tgt = self::encode_object($i['target']); - if ($tgt) { - $ret['target'] = $tgt; - } - } -*/ + if (intval($i['item_private']) === 0) { $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; } @@ -846,32 +807,12 @@ class Activity { $ret['type'] = self::activity_mapper($i['verb']); if ((isset($i['item_deleted']) && intval($i['item_deleted'])) && !$recurse) { + $is_response = false; - if ($i['verb'] === 'Add' && str_contains($i['tgt_type'], 'Collection')) { - $ret['id'] = str_replace('/item/', '/activity/', $i['mid']) . '#Remove'; - $ret['type'] = 'Remove'; - if (is_string($i['obj'])) { - $obj = json_decode($i['obj'], true); - } - elseif(is_array($i['obj'])) { - $obj = $i['obj']; - } - if (isset($obj['id'])) { - $ret['object'] = $obj['id']; - } - else { - $ret['object'] = str_replace('/item/', '/activity/', $i['mid']); - } - $ret['target'] = is_array($i['target']) ? $i['target'] : json_decode($i['target'], true); - - return $ret; - } - - $is_response = ActivityStreams::is_response_activity($ret['type']); - - if ($is_response) { + if (ActivityStreams::is_response_activity($ret['type'])) { $ret['type'] = 'Undo'; $fragment = 'undo'; + $is_response = true; } else { $ret['type'] = 'Delete'; @@ -994,28 +935,9 @@ class Activity { // inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.), // but *not* for comments and RSVPs, where it should only be present in the object - if (!in_array($ret['type'], ['Create', 'Update', 'Add', 'Remove', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject'])) { + if (!in_array($ret['type'], ['Create', 'Update', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject'])) { $ret['inReplyTo'] = ((strpos($i['thr_parent'], 'http') === 0) ? $i['thr_parent'] : z_root() . '/item/' . urlencode($i['thr_parent'])); } - - $cnv = IConfig::Get($i['parent'], 'activitypub', 'context'); - if (!$cnv) { - $cnv = $item['parent_mid']; - } - } - - if (empty($cnv)) { - $cnv = IConfig::Get($i, 'activitypub', 'context'); - if (!$cnv) { - $cnv = $i['parent_mid']; - } - } - - if (!empty($cnv)) { - if (is_string($cnv) && str_starts_with($cnv, z_root())) { - $cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv); - } - $ret['context'] = $cnv; } $actor = self::encode_person($i['author'], false); @@ -1088,7 +1010,6 @@ class Activity { call_hooks('encode_activity', $hookinfo); return $hookinfo['encoded']; - } // Returns an array of URLS for any mention tags found in the item array $i. @@ -2946,10 +2867,6 @@ class Activity { // This isn't perfect but the best we can do for now. $item['comment_policy'] = ((isset($act->data['commentPolicy'])) ? $act->data['commentPolicy'] : 'authenticated'); - if (!empty($act->obj['context'])) { - IConfig::Set($item, 'activitypub', 'context', $act->obj['context'], 1); - } - IConfig::Set($item, 'activitypub', 'recips', $act->raw_recips); if (intval($act->sigok)) { @@ -3137,13 +3054,6 @@ class Activity { } $a = new ActivityStreams($n); - if ($a->type === 'Announce' && is_array($a->obj) - && array_key_exists('object', $a->obj) && array_key_exists('actor', $a->obj)) { - // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) - // Reparse the encapsulated Activity and use that instead - logger('relayed activity', LOGGER_DEBUG); - $a = new ActivityStreams($a->obj); - } logger($a->debug(), LOGGER_DATA); @@ -3152,6 +3062,24 @@ class Activity { break; } + if (in_array($a->type, ['Add', 'Remove']) + && is_array($a->obj) + && array_key_exists('object', $a->obj) + && array_key_exists('actor', $a->obj) + && !empty($a->tgt)) { + + logger('unsupported collection operation', LOGGER_DEBUG); + return; + } + + if ($a->type === 'Announce' && is_array($a->obj) + && array_key_exists('object', $a->obj) && array_key_exists('actor', $a->obj)) { + // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) + // Reparse the encapsulated Activity and use that instead + logger('relayed activity', LOGGER_DEBUG); + $a = new ActivityStreams($a->obj); + } + $item = Activity::decode_note($a); if (!$item) { @@ -3759,70 +3687,5 @@ class Activity { } } - public static function addToCollection($channel, $object, $target, $sourceItem = null, $deliver = true) { - if (!isset($channel['xchan_hash'])) { - $channel = channelx_by_hash($channel['channel_hash']); - } - - $item = ((new Item()) - ->setUid($channel['channel_id']) - ->setVerb('Add') - ->setAuthorXchan($channel['channel_hash']) - ->setOwnerXchan($channel['channel_hash']) - ->setObj($object) - ->setObjType($object['type']) - ->setParentMid(str_replace('/conversation/','/item/', $target)) - ->setThrParent(str_replace('/conversation/','/item/', $target)) - ->setApproved($object['object']['id'] ?? '') - ->setReplyto(z_root() . '/channel/' . $channel['channel_address']) - ->setTgtType('Collection') - ->setTarget([ - 'id' => str_replace('/item/','/conversation/', $target), - 'type' => 'Collection', - 'attributedTo' => z_root() . '/channel/' . $channel['channel_address'], - ]) - ); - if ($sourceItem) { - $item->setAllowCid($sourceItem['allow_cid']) - ->setAllowGid($sourceItem['allow_gid']) - ->setDenyCid($sourceItem['deny_cid']) - ->setDenyGid($sourceItem['deny_gid']) - ->setPrivate($sourceItem['item_private']) - ->setNocomment($sourceItem['item_nocomment']) - ->setCommentPolicy($sourceItem['comment_policy']) - ->setPostopts($sourceItem['postopts']); - } - $result = post_activity_item($item->toArray(), deliver: $deliver, channel: $channel, observer: $channel, addAndSync: false); - logger('addToCollection: ' . print_r($result, true)); - return $result; - } - - public static function removeFromCollection($channel, $object, $target, $deliver = true) { - if (!isset($channel['xchan_hash'])) { - $channel = channelx_by_hash($channel['channel_hash']); - } - - $item = ((new Item()) - ->setUid($channel['channel_id']) - ->setVerb('Remove') - ->setAuthorXchan($channel['channel_hash']) - ->setOwnerXchan($channel['channel_hash']) - ->setObj($object) - ->setObjType($object['type']) - ->setParentMid(str_replace('/conversation/','/item/', $target)) - ->setThrParent(str_replace('/conversation/','/item/', $target)) - ->setReplyto(z_root() . '/channel/' . $channel['channel_address']) - ->setTgtType('Collection') - ->setTarget([ - 'id' => str_replace('/item/','/conversation/', $target), - 'type' => 'Collection', - 'attributedTo' => z_root() . '/channel/' . $channel['channel_address'] - ]) - ); - - $result = post_activity_item($item->toArray(), deliver: $deliver, channel: $channel, observer: $channel, addAndSync: false); - logger('removeFromCollection: ' . print_r($result, true)); - return $result; - } } diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 41fec64d8..05134f433 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1134,7 +1134,6 @@ class Libzot { } $message_request = false; - $is_collection_operation = false; $has_data = array_key_exists('data', $env) && $env['data']; @@ -1142,44 +1141,26 @@ class Libzot { $AS = null; - if ($env['encoding'] === 'activitystreams') { $AS = new ActivityStreams($data); - - logger($AS->debug(), LOGGER_DATA); - if (!$AS->is_valid()) { logger('Activity rejected: ' . print_r($data, true)); return; } - // process add/remove from collection separately, as it requires a target. - // use the raw object, as it will not include actor expansion if (in_array($AS->type, ['Add', 'Remove']) && is_array($AS->obj) && array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj) && !empty($AS->tgt)) { - hz_syslog('relayed collection operation', LOGGER_DEBUG); - $is_collection_operation = true; - - $original_id = $AS->id; - $original_type = $AS->type; - - $raw_activity = $AS->data; - - $AS = new ActivityStreams($raw_activity['object'], portable_id: $env['sender']); - - // Store the original activity id and type for later usage - $AS->meta['original_id'] = $original_id; - $AS->meta['original_type'] = $original_type; + logger('unsupported collection operation', LOGGER_DEBUG); + return; } if (is_array($AS->obj)) { $item = Activity::decode_note($AS); - if (!$item) { logger('Could not decode activity: ' . print_r($AS, true)); return; @@ -1189,7 +1170,7 @@ class Libzot { $item = []; } - + logger($AS->debug(), LOGGER_DATA); } @@ -1332,12 +1313,7 @@ class Libzot { $relay = (($env['type'] === 'response') ? true : false); - if($is_collection_operation) - hz_syslog('col'); - else - hz_syslog('not col'); - - $result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request, false, $is_collection_operation); + $result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request); Activity::init_background_fetch($env['sender']); } @@ -1553,7 +1529,7 @@ class Libzot { * @return array */ - static function process_delivery($sender, $act, $arr, $deliveries, $relay, $public = false, $request = false, $force = false, $is_collection_operation = false) { + static function process_delivery($sender, $act, $arr, $deliveries, $relay, $public = false, $request = false, $force = false) { $result = []; // We've validated the sender. Now make sure that the sender is the owner or author @@ -1581,14 +1557,6 @@ class Libzot { $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); - $conversation_operation = $is_collection_operation && isset($arr['target']['attributedTo']); - - if (str_contains($arr['tgt_type'], 'Collection') && !$relay && !$conversation_operation) { - $DR->update('not a collection activity'); - $result[] = $DR->get(); - continue; - } - if (($act) && ($act->obj) && (!is_array($act->obj))) { // The initial object fetch failed using the sys channel credentials. // Try again using the delivery channel credentials. @@ -1622,8 +1590,6 @@ class Libzot { * */ - - if ($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && !str_starts_with($arr['mid'], z_root())) { $DR->update('self delivery ignored'); $result[] = $DR->get(); @@ -1864,12 +1830,6 @@ class Libzot { } } - if($is_collection_operation) - hz_syslog('col1'); - else - hz_syslog('not col1'); - - // This is used to fetch allow/deny rules if either the sender // or owner is a connection. post_is_importable() evaluates all of them $abook = q("select * from abook where abook_channel = %d and ( abook_xchan = '%s' OR abook_xchan = '%s' )", @@ -1878,15 +1838,11 @@ class Libzot { dbesc($arr['author_xchan']) ); - // Reactions such as like and dislike could have an mid with /activity/ in it. + // reactions such as like and dislike could have an mid with /activity/ in it. // Check for both forms in order to prevent duplicates. - - // If we process an add/remove activity, look for the original activity id instead of the object id - $sql_mid = (($is_collection_operation && $relay && $channel['channel_hash'] === $arr['owner_xchan']) ? $act->meta['original_id'] : $arr['mid']); - - $r = q("select * from item where mid in ('%s', '%s') and uid = %d limit 1", - dbesc($sql_mid), - dbesc(reverse_activity_mid($sql_mid)), + $r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1", + dbesc($arr['mid']), + dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])), intval($channel['channel_id']) ); @@ -1915,29 +1871,21 @@ class Libzot { $DR->update('update ignored'); $result[] = $DR->get(); } - - if ($relay && $channel['channel_hash'] === $item_result['item']['owner_xchan'] && $item_result['item']['verb'] !== 'Add' && !$is_collection_operation) { - $approval = Activity::addToCollection($channel, $act->data, $item_result['item']['parent_mid'], $item_result['item'], deliver: false); - } - } else { $DR->update('update ignored'); $result[] = $DR->get(); - // We need this line to ensure wall-to-wall comments and add/remove activities are relayed (by falling through to the relay bit), + // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit), // and at the same time not relay any other relayable posts more than once, because to do so is very wasteful. if (!intval($r[0]['item_origin'])) continue; } - - } else { $arr['aid'] = $channel['channel_account_id']; $arr['uid'] = $channel['channel_id']; - // if it's a sourced post, call the post_local hooks as if it were // posted locally so that crosspost connectors will be triggered. $item_source = check_item_source($arr['uid'], $arr); @@ -1966,15 +1914,10 @@ class Libzot { } if (post_is_importable($arr['uid'], $arr, $abook)) { - $item_result = item_store($arr, addAndSync: false); - + $item_result = item_store($arr); if ($item_result['success']) { $item_id = $item_result['item_id']; - if ($relay && $channel['channel_hash'] === $item_result['item']['owner_xchan'] && $item_result['item']['verb'] !== 'Add' && !$is_collection_operation) { - $approval = Activity::addToCollection($channel, $act->data, $item_result['item']['parent_mid'], $item_result['item'], deliver: false); - } - if ($item_source && in_array($item_result['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) { event_addtocal($item_id, $channel['channel_id']); } @@ -2023,10 +1966,6 @@ class Libzot { if ($relay && $item_id && $stored['item_blocked'] !== ITEM_MODERATED) { logger('Invoking relay'); Master::Summon(['Notifier', 'relay', intval($item_id)]); - if (!empty($approval) && $approval['item_id']) { - Master::Summon(['Notifier', 'relay', intval($approval['item_id'])]); - } - $DR->addto_update('relayed'); $result[] = $DR->get(); } @@ -2080,7 +2019,12 @@ class Libzot { $AS = new ActivityStreams($activity); - if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj) + if (!$AS->is_valid()) { + logger('Fetched activity rejected: ' . print_r($activity, true)); + continue; + } + + if ($AS->type === 'Announce' && is_array($AS->obj) && array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj)) { // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) // Reparse the encapsulated Activity and use that instead @@ -2088,33 +2032,14 @@ class Libzot { $AS = new ActivityStreams($AS->obj); } - // process add/remove from collection separately, as it requires a target. - // use the raw object, as it will not include actor expansion if (in_array($AS->type, ['Add', 'Remove']) && is_array($AS->obj) && array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj) && !empty($AS->tgt)) { - logger('relayed collection operation', LOGGER_DEBUG); - - $is_collection_operation = true; - - $original_id = $AS->id; - $original_type = $AS->type; - - $raw_activity = $AS->data; - - $AS = new ActivityStreams($raw_activity['object'], portable_id: $env['sender']); - - // Store the original activity id and type for later usage - $AS->meta['original_id'] = $original_id; - $AS->meta['original_type'] = $original_type; - } - - if (!$AS->is_valid()) { - logger('Fetched activity rejected: ' . print_r($activity, true)); - continue; + logger('unsupported collection operation', LOGGER_DEBUG); + return; } // logger($AS->debug()); @@ -2305,7 +2230,7 @@ class Libzot { } - $x = item_store_update($item, addAndSync: false); + $x = item_store_update($item); // If we're updating an event that we've saved locally, we store the item info first // because event_addtocal will parse the body to get the 'new' event details |