From 2590e3c99be36f806fe25dd6db0504e853669fde Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 1 Jan 2024 20:04:24 +0000 Subject: reveal repeat --- Zotlabs/Lib/Activity.php | 6 ++++-- Zotlabs/Lib/ThreadItem.php | 16 ++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 835909849..0dfa15aea 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1194,7 +1194,7 @@ class Activity { $acts = [ 'http://activitystrea.ms/schema/1.0/post' => 'Create', - 'http://activitystrea.ms/schema/1.0/share' => 'Announce', + //'http://activitystrea.ms/schema/1.0/share' => 'Announce', 'http://activitystrea.ms/schema/1.0/update' => 'Update', 'http://activitystrea.ms/schema/1.0/like' => 'Like', 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', @@ -1206,6 +1206,7 @@ class Activity { 'http://purl.org/zot/activity/attendyes' => 'Accept', 'http://purl.org/zot/activity/attendno' => 'Reject', 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept', + 'Announce' => 'Announce', 'Invite' => 'Invite', 'Delete' => 'Delete', 'Undo' => 'Undo' @@ -1242,7 +1243,7 @@ class Activity { $acts = [ 'http://activitystrea.ms/schema/1.0/post' => 'Create', - 'http://activitystrea.ms/schema/1.0/share' => 'Announce', + // 'http://activitystrea.ms/schema/1.0/share' => 'Announce', 'http://activitystrea.ms/schema/1.0/update' => 'Update', 'http://activitystrea.ms/schema/1.0/like' => 'Like', 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', @@ -1254,6 +1255,7 @@ class Activity { 'http://purl.org/zot/activity/attendyes' => 'Accept', 'http://purl.org/zot/activity/attendno' => 'Reject', 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept', + 'Announce' => 'Announce', 'Invite' => 'Invite', 'Delete' => 'Delete', 'Undo' => 'Undo' diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 037ddb19e..3cdb59e5f 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -121,12 +121,14 @@ class ThreadItem { $locktype = 0; } - $shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && ($item['item_private'] != 1)) ? true : false); + $shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && (intval($item['item_private']) === 0)) ? true : false); // allow an exemption for sharing stuff from your private feeds if($item['author']['xchan_network'] === 'rss') $shareable = true; + $repeatable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && (intval($item['item_private']) === 0) && (in_array($item['author']['xchan_network'], ['zot6', 'activitypub']))) ? true : false); + // @fixme // Have recently added code to properly handle polls in group reshares by redirecting all of the poll responses to the group. // Sharing a poll using a regular embedded share is harder because the poll will need to fork. This is due to comment permissions. @@ -315,13 +317,11 @@ class ThreadItem { $share = []; $embed = []; if ($shareable) { - // This actually turns out not to be possible in some protocol stacks without opening up hundreds of new issues. - // Will allow it only for uri resolvable sources. - if(strpos($item['mid'],'http') === 0) { - //Not yet ready for primetime - //$share = array( t('Repeat This'), t('repeat')); - } - $embed = [t('Share This'), t('share')]; + $embed = [t('Share'), t('share')]; + } + + if ($repeatable) { + $share = [t('Repeat'), t('repeat')]; } $dreport = ''; -- cgit v1.2.3 From 852678e238eaa28199640b4b2a856e53d707ca24 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 3 Jan 2024 19:20:28 +0000 Subject: port multibase and jcsedssa2022 libs from streams --- Zotlabs/Lib/JcsEddsa2022.php | 91 ++++++++++++++++++++++++++++++++++++++++++++ Zotlabs/Lib/Multibase.php | 34 +++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 Zotlabs/Lib/JcsEddsa2022.php create mode 100644 Zotlabs/Lib/Multibase.php (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/JcsEddsa2022.php b/Zotlabs/Lib/JcsEddsa2022.php new file mode 100644 index 000000000..cb5462952 --- /dev/null +++ b/Zotlabs/Lib/JcsEddsa2022.php @@ -0,0 +1,91 @@ +publicKey($channel['channel_epubkey']); + $options = [ + 'type' => 'DataIntegrityProof', + 'cryptosuite' => 'eddsa-jcs-2022', + 'created' => datetime_convert(format: ATOM_TIME), + 'verificationMethod' => channel_url($channel) . '#' . $pubkey, + 'proofPurpose' => 'assertionMethod', + ]; + + $optionsHash = $this->hash($this->signableOptions($options), true); + $dataHash = $this->hash($this->signableData($data), true); + + $options['proofValue'] = 'z' . $base58->encode(sodium_crypto_sign_detached($optionsHash . $dataHash, + sodium_base642bin($channel['channel_eprvkey'], SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING))); + + return $options; + } + + public function verify($data, $publicKey) { + $base58 = new Base58(); + $encodedSignature = $data['proof']['proofValue'] ?? ''; + if (!str_starts_with($encodedSignature,'z')) { + return false; + } + $encodedSignature = substr($encodedSignature, 1); + $optionsHash = $this->hash($this->signableOptions($data['proof']), true); + $dataHash = $this->hash($this->signableData($data),true); + + try { + $result = sodium_crypto_sign_verify_detached($base58->decode($encodedSignature), $optionsHash . $dataHash, + (new Multibase())->decode($publicKey, true)); + } + catch (\Exception $e) { + logger('verify exception:' . $e->getMessage()); + } + + logger('SignatureVerify (eddsa-jcs-2022) ' . (($result) ? 'true' : 'false')); + + return $result; + } + + public function signableData($data) { + $signableData = []; + if ($data) { + foreach ($data as $k => $v) { + if ($k != 'proof') { + $signableData[$k] = $v; + } + } + } + return $signableData; + } + + public function signableOptions($options) { + $signableOptions = []; + + if ($options) { + foreach ($options as $k => $v) { + if ($k !== 'proofValue') { + $signableOptions[$k] = $v; + } + } + } + return $signableOptions; + } + + public function hash($obj, $binary = false) { + return hash('sha256', $this->canonicalize($obj), $binary); + } + + public function canonicalize($data) { + $canonicalization = JsonCanonicalizatorFactory::getInstance(); + return $canonicalization->canonicalize($data); + } + +} diff --git a/Zotlabs/Lib/Multibase.php b/Zotlabs/Lib/Multibase.php new file mode 100644 index 000000000..099723630 --- /dev/null +++ b/Zotlabs/Lib/Multibase.php @@ -0,0 +1,34 @@ +encode($raw); + } + + public function secretKey($key) { + $base58 = new Base58(); + $raw = hex2bin('8026') . sodium_base642bin($key, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING); + return 'z' . $base58->encode($raw); + } + + public function decode($key, $binary = false) { + $base58 = new Base58(); + $key = substr($key,1); + $raw = $base58->decode($key); + $binaryKey = substr($raw, 2); + return $binary ? $binaryKey : sodium_bin2base64($binaryKey, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING); + } + +} -- cgit v1.2.3 From 99c5a4e2f8660fad1812849df47a8a3a3377d9a9 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 6 Jan 2024 16:44:17 +0000 Subject: we do not use named params yet --- Zotlabs/Lib/JcsEddsa2022.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/JcsEddsa2022.php b/Zotlabs/Lib/JcsEddsa2022.php index cb5462952..425627b62 100644 --- a/Zotlabs/Lib/JcsEddsa2022.php +++ b/Zotlabs/Lib/JcsEddsa2022.php @@ -17,7 +17,7 @@ class JcsEddsa2022 { $options = [ 'type' => 'DataIntegrityProof', 'cryptosuite' => 'eddsa-jcs-2022', - 'created' => datetime_convert(format: ATOM_TIME), + 'created' => datetime_convert('UTC', 'UTC', 'now', ATOM_TIME), 'verificationMethod' => channel_url($channel) . '#' . $pubkey, 'proofPurpose' => 'assertionMethod', ]; -- cgit v1.2.3 From 87775ae37ad7f8226f7413d28e96fd23967c7659 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 7 Jan 2024 19:58:09 +0000 Subject: ekey and xchan_updated updates --- Zotlabs/Lib/Libsync.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index 5f183192d..3130290f7 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -325,9 +325,6 @@ class Libsync { if (array_key_exists('channel', $arr) && is_array($arr['channel']) && count($arr['channel'])) { - $remote_channel = $arr['channel']; - $remote_channel['channel_id'] = $channel['channel_id']; - if (array_key_exists('channel_pageflags', $arr['channel'])) { // Several pageflags are site-specific and cannot be sync'd. @@ -339,6 +336,8 @@ class Libsync { } + $columns = db_columns('channel'); + $disallowed = [ 'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey', 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', @@ -349,16 +348,21 @@ class Libsync { 'channel_a_delegate' ]; - $clean = []; + if (empty($channel['channel_epubkey']) && empty($channel['channel_eprvkey'])) { + $eckey = sodium_crypto_sign_keypair(); + $channel['channel_epubkey'] = sodium_bin2base64(sodium_crypto_sign_publickey($eckey), SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING); + $channel['channel_eprvkey'] = sodium_bin2base64(sodium_crypto_sign_secretkey($eckey), SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING); + } + foreach ($arr['channel'] as $k => $v) { - if (in_array($k, $disallowed)) + if (in_array($k, $disallowed)) { + continue; + } + if (!in_array($k, $columns)) { continue; - $clean[$k] = $v; - } - if (count($clean)) { - foreach ($clean as $k => $v) { - dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) . "' where channel_id = " . intval($channel['channel_id'])); } + $r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) + . "' where channel_id = " . intval($channel['channel_id'])); } } -- cgit v1.2.3 From 58593d7da6a893e681b7c64fdf21a02c93dfa0d0 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 10 Jan 2024 13:33:57 +0000 Subject: prepare outbound fep-8b32 (object integrity) but do not enable yet since the additional context seems to break ldsig for some reason, introduce Activity::build_packet() and Activity::ap_context() to reduce code duplication, implement fep-2c59 (webfinger) and some cleanup --- Zotlabs/Lib/Activity.php | 76 +++++++++++++++++++++++++++++++++++++++++ Zotlabs/Lib/ActivityStreams.php | 1 + 2 files changed, 77 insertions(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 0dfa15aea..766b4ed91 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -4211,4 +4211,80 @@ class Activity { } + public static function ap_context($contextType = null): array { + return ['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + // '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) + ]]; + } + + public static function ap_schema($contextType = null): array { + // $contextType is reserved for future use so that the caller can specify + // a limited subset of the entire schema definition for particular activities. + + return [ + 'zot' => z_root() . '/apschema#', + 'schema' => 'http://schema.org#', + 'ostatus' => 'http://ostatus.org#', + 'diaspora' => 'https://diasporafoundation.org/ns/', + + 'commentPolicy' => 'zot:commentPolicy', + 'locationAddress' => 'zot:locationAddress', + 'locationPrimary' => 'zot:locationPrimary', + 'locationDeleted' => 'zot:locationDeleted', + 'nomadicLocation' => 'zot:nomadicLocation', + 'nomadicHubs' => 'zot:nomadicHubs', + 'emojiReaction' => 'zot:emojiReaction', + 'expires' => 'zot:expires', + 'directMessage' => 'zot:directMessage', + 'Bookmark' => 'zot:Bookmark', + 'Category' => 'zot:Category', + + 'PropertyValue' => 'schema:PropertyValue', + 'value' => 'schema:value', + + 'conversation' => 'ostatus:conversation', + + 'guid' => 'diaspora:guid', + + 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', + 'Hashtag' => 'as:Hashtag' + + ]; + + } + + /** + * @brief Builds the activity packet and signs it if $channel is provided. + * + * @param array $obj + * @param array $channel (optional) default [] + * @param bool $json_encode (optional) default true + * @return string|array + */ + + public static function build_packet(array $obj, array $channel = [], bool $json_encode = true): string|array { + $arr = array_merge(Activity::ap_context(), $obj); + + if ($channel) { + // $proof = (new JcsEddsa2022)->sign($arr, $channel); + // $arr['proof'] = $proof; + + $signature = LDSignatures::sign($arr, $channel); + $arr['signature'] = $signature; + } + + if ($json_encode) { + return json_encode($arr, JSON_UNESCAPED_SLASHES); + } + + return $arr; + } + + } diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index 4c3e3d8f8..c32f82e33 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -28,6 +28,7 @@ class ActivityStreams { public $sigok = false; public $recips = null; public $raw_recips = null; + public $saved_recips = null; /** * @brief Constructor for ActivityStreams. -- cgit v1.2.3 From e8dd2c28ff520a3abaa728743a49e05188ce59a5 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 13 Jan 2024 08:50:57 +0000 Subject: make our jsonld parser happy --- Zotlabs/Lib/Activity.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 766b4ed91..8cc359f44 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -4229,7 +4229,7 @@ class Activity { return [ 'zot' => z_root() . '/apschema#', - 'schema' => 'http://schema.org#', + 'schema' => 'http://schema.org/', 'ostatus' => 'http://ostatus.org#', 'diaspora' => 'https://diasporafoundation.org/ns/', @@ -4272,8 +4272,8 @@ class Activity { $arr = array_merge(Activity::ap_context(), $obj); if ($channel) { - // $proof = (new JcsEddsa2022)->sign($arr, $channel); - // $arr['proof'] = $proof; + $proof = (new JcsEddsa2022)->sign($arr, $channel); + $arr['proof'] = $proof; $signature = LDSignatures::sign($arr, $channel); $arr['signature'] = $signature; -- cgit v1.2.3 From 28b604c7c7bc10ac5ec69d16c3bf5f792f720db9 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 13 Jan 2024 13:46:40 +0000 Subject: typo --- Zotlabs/Lib/Activity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 8cc359f44..b841ce1cd 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -4229,7 +4229,7 @@ class Activity { return [ 'zot' => z_root() . '/apschema#', - 'schema' => 'http://schema.org/', + 'schema' => 'http://schema.org#', 'ostatus' => 'http://ostatus.org#', 'diaspora' => 'https://diasporafoundation.org/ns/', -- cgit v1.2.3 From 1d652cfcbd13bf38954549d8cb089a59ccd25d01 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 13 Jan 2024 15:09:39 +0000 Subject: expose epubkey in zotinfo --- Zotlabs/Lib/Libzot.php | 1 + 1 file changed, 1 insertion(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 3f8685397..9c92f7523 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -2814,6 +2814,7 @@ class Libzot { ]; $ret['public_key'] = $e['channel_pubkey']; + $ret['ed25519_key'] = $e['xchan_epubkey']; $ret['signing_algorithm'] = 'rsa-sha256'; $ret['username'] = $e['channel_address']; $ret['name'] = $e['channel_name']; -- cgit v1.2.3 From 477b1535a2fd6b70bb5e436fbab517ce620c7169 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 13 Jan 2024 15:28:20 +0000 Subject: start storing epubkeys in libzot --- Zotlabs/Lib/Libzot.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 9c92f7523..41c091fb6 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -759,12 +759,13 @@ class Libzot { || ($r[0]['xchan_connurl'] != $arr['primary_location']['connections_url']) || ($r[0]['xchan_addr'] != $arr['primary_location']['address']) || ($r[0]['xchan_follow'] != $arr['primary_location']['follow_url']) + || (isset($arr['ed25519_key']) && $r[0]['xchan_epubkey'] != $arr['ed25519_key']) || ($r[0]['xchan_connpage'] != $arr['connect_url']) || ($r[0]['xchan_url'] != $arr['primary_location']['url']) || $hidden_changed || $adult_changed || $deleted_changed || $pubforum_changed) { $rup = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s', xchan_connpage = '%s', xchan_hidden = %d, xchan_selfcensored = %d, xchan_deleted = %d, xchan_pubforum = %d, - xchan_addr = '%s', xchan_url = '%s' where xchan_hash = '%s'", + xchan_addr = '%s', xchan_url = '%s', xchan_epubkey = '%s' where xchan_hash = '%s'", dbesc(($arr['name']) ? escape_tags($arr['name']) : '-'), dbesc($arr['name_updated']), dbesc($arr['primary_location']['connections_url']), @@ -776,6 +777,7 @@ class Libzot { intval($arr['public_forum']), dbesc(escape_tags($arr['primary_location']['address'])), dbesc(escape_tags($arr['primary_location']['url'])), + dbesc($arr['xchan_epubkey'] ?? ''), dbesc($xchan_hash) ); @@ -799,6 +801,7 @@ class Libzot { 'xchan_guid' => $arr['id'], 'xchan_guid_sig' => $arr['id_sig'], 'xchan_pubkey' => $arr['public_key'], + 'xchan_epubkey' => $arr['xchan_epubkey'] ?? '', 'xchan_photo_mimetype' => $arr['photo']['type'], 'xchan_photo_l' => $arr['photo']['url'], 'xchan_addr' => escape_tags($arr['primary_location']['address']), -- cgit v1.2.3 From 9cb95f6065353ac93e2ec84c7fe009ee3b26a72b Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 13 Jan 2024 16:19:53 +0000 Subject: store epubkey in actor_store --- Zotlabs/Lib/Activity.php | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index b841ce1cd..93f50fc56 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1680,7 +1680,7 @@ class Activity { $name = t('Unknown'); } - $webfinger_addr = ''; + $webfinger_addr = $person_obj['webfinger'] ?? ''; $hostname = ''; $baseurl = ''; $site_url = ''; @@ -1692,7 +1692,7 @@ class Activity { $site_url = $m['scheme'] . '://' . $m['host']; } - if (!empty($person_obj['preferredUsername']) && $hostname) { + if (!$webfinger_addr && !empty($person_obj['preferredUsername']) && $hostname) { $webfinger_addr = escape_tags($person_obj['preferredUsername']) . '@' . $hostname; } @@ -1746,6 +1746,7 @@ class Activity { $profile = $url; } + $pubkey = ''; if (array_key_exists('publicKey', $person_obj) && array_key_exists('publicKeyPem', $person_obj['publicKey'])) { if ($person_obj['id'] === $person_obj['publicKey']['owner']) { $pubkey = $person_obj['publicKey']['publicKeyPem']; @@ -1755,6 +1756,18 @@ class Activity { } } + $epubkey = ''; + // TODO: We should probably also deal with arrays here. + // It is not clear yet which key we want to store if we got more than one though. + if (isset($person_obj['assertionMethod']['publicKeyMultibase'])) { + if ($person_obj['id'] === $person_obj['assertionMethod']['controller']) { + $epubkey = $person_obj['assertionMethod']['publicKeyMultibase']; + if ($person_obj['assertionMethod']['type'] === 'Multikey') { + $epubkey = $person_obj['assertionMethod']['publicKeyMultibase']; + } + } + } + $group_actor = ($person_obj['type'] === 'Group'); $r = q("select * from xchan join hubloc on xchan_hash = hubloc_hash where xchan_hash = '%s'", @@ -1775,10 +1788,11 @@ class Activity { ); // update existing xchan record - q("update xchan set xchan_name = '%s', xchan_pubkey = '%s', xchan_addr = '%s', xchan_network = 'activitypub', xchan_name_date = '%s', xchan_pubforum = %d where xchan_hash = '%s'", - dbesc(escape_tags($name)), - dbesc(escape_tags($pubkey)), - dbesc(escape_tags($webfinger_addr)), + q("update xchan set xchan_name = '%s', xchan_pubkey = '%s', xchan_epubkey = '%s', xchan_addr = '%s', xchan_network = 'activitypub', xchan_name_date = '%s', xchan_pubforum = %d where xchan_hash = '%s'", + dbesc($name), + dbesc($pubkey), + dbesc($epubkey), + dbesc($webfinger_addr), dbescdate(datetime_convert()), intval($group_actor), dbesc($url) @@ -1786,7 +1800,7 @@ class Activity { // update existing hubloc record q("update hubloc set hubloc_addr = '%s', hubloc_network = 'activitypub', hubloc_url = '%s', hubloc_host = '%s', hubloc_callback = '%s', hubloc_updated = '%s', hubloc_id_url = '%s' where hubloc_hash = '%s'", - dbesc(escape_tags($webfinger_addr)), + dbesc($webfinger_addr), dbesc($baseurl), dbesc($hostname), dbesc($inbox), @@ -1802,13 +1816,14 @@ class Activity { [ 'xchan_hash' => $url, 'xchan_guid' => $url, - 'xchan_pubkey' => escape_tags($pubkey), + 'xchan_pubkey' => $pubkey, + 'xchan_epubkey' => $epubkey, 'xchan_addr' => $webfinger_addr, 'xchan_url' => $profile, - 'xchan_name' => escape_tags($name), - 'xchan_photo_l' => z_root() . '/' . get_default_profile_photo(), - 'xchan_photo_m' => z_root() . '/' . get_default_profile_photo(80), - 'xchan_photo_s' => z_root() . '/' . get_default_profile_photo(48), + 'xchan_name' => $name, + 'xchan_photo_l' => z_root() . '/' . get_default_profile_photo(), + 'xchan_photo_m' => z_root() . '/' . get_default_profile_photo(80), + 'xchan_photo_s' => z_root() . '/' . get_default_profile_photo(48), 'xchan_name_date' => datetime_convert(), 'xchan_network' => 'activitypub', 'xchan_pubforum' => intval($group_actor) -- cgit v1.2.3 From c59701740294ee8986942579abe18f82c4dee176 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 13 Jan 2024 17:38:31 +0000 Subject: fix some deprecation warnings --- Zotlabs/Lib/DReport.php | 1 + 1 file changed, 1 insertion(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/DReport.php b/Zotlabs/Lib/DReport.php index e22ed65be..f4f098d19 100644 --- a/Zotlabs/Lib/DReport.php +++ b/Zotlabs/Lib/DReport.php @@ -6,6 +6,7 @@ class DReport { private $location; private $sender; private $recipient; + private $name; private $message_id; private $status; private $date; -- cgit v1.2.3 From fa7aa6cedb83279252d1e26bb58227a6f99df9ed Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 13 Jan 2024 20:38:34 +0000 Subject: start checking integrity proofs, remove signature prior to verify, iterate trough the array to find the desired ekey in actor_store() --- Zotlabs/Lib/Activity.php | 12 ++++----- Zotlabs/Lib/ActivityStreams.php | 56 ++++++++++++++++++++++++++++++++++++----- Zotlabs/Lib/JcsEddsa2022.php | 3 ++- 3 files changed, 57 insertions(+), 14 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 93f50fc56..6c680c56e 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1757,14 +1757,12 @@ class Activity { } $epubkey = ''; - // TODO: We should probably also deal with arrays here. - // It is not clear yet which key we want to store if we got more than one though. - if (isset($person_obj['assertionMethod']['publicKeyMultibase'])) { - if ($person_obj['id'] === $person_obj['assertionMethod']['controller']) { + foreach($person_obj['assertionMethod'] as $am) { + if ($person_obj['id'] === $am['controller'] && + $am['type'] === 'Multikey' && + str_starts_with($am['publicKeyMultibase'], 'z6Mk') + ) { $epubkey = $person_obj['assertionMethod']['publicKeyMultibase']; - if ($person_obj['assertionMethod']['type'] === 'Multikey') { - $epubkey = $person_obj['assertionMethod']['publicKeyMultibase']; - } } } diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index c32f82e33..98fc73462 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -24,7 +24,7 @@ class ActivityStreams { public $origin = null; public $owner = null; public $signer = null; - public $ldsig = null; + public $sig = null; public $sigok = false; public $recips = null; public $raw_recips = null; @@ -97,11 +97,19 @@ class ActivityStreams { $this->origin = $this->get_compound_property('origin'); $this->recips = $this->collect_recips(); - $this->ldsig = $this->get_compound_property('signature'); - if ($this->ldsig) { - $this->signer = $this->get_actor('creator', $this->ldsig); - if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) { - $this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']); + $this->sig = $this->get_compound_property('proof'); + if ($this->sig) { + $this->checkEddsaSignature(); // will set signer and sigok if everything works out + } + + // Try LDSignatures if edsig failed + if (!$this->sigok) { + $this->sig = $this->get_compound_property('signature'); + if ($this->sig) { + $this->signer = $this->get_actor('creator', $this->sig); + if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) { + $this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']); + } } } @@ -490,4 +498,40 @@ class ActivityStreams { } + public function checkEddsaSignature() { + $signer = $this->get_property_obj('verificationMethod', $this->sig); + + $parseUrl = parse_url($signer); + if (!empty($parseUrl['fragment']) && str_starts_with($parseUrl['fragment'],'z6Mk')) { + $publicKey = $parseUrl['fragment']; + unset($parseUrl['fragment']); + unset($parseUrl['query']); + } + + $url = unparse_url($parseUrl); + //$this->signer = [ 'id' => $url ]; + + $hublocs = Activity::get_actor_hublocs($url); + $hasStoredKey = false; + if ($hublocs) { + foreach ($hublocs as $hubloc) { + if ($publicKey && $hubloc['xchan_epubkey'] === $publicKey) { + $hasStoredKey = true; + break; + } + } + } + if (!$hasStoredKey) { + $this->signer = Activity::get_actor($url); + if ($this->signer + && !empty($this->signer['assertionMethod']) + && !empty($this->signer['assertionMethod']['publicKeyMultibase'])) { + $publicKey = $this->signer['assertionMethod']['publicKeyMultibase']; + } + } + if ($publicKey) { + $this->sigok = (new JcsEddsa2022)->verify($this->data, $publicKey); + } + } + } diff --git a/Zotlabs/Lib/JcsEddsa2022.php b/Zotlabs/Lib/JcsEddsa2022.php index 425627b62..14f16c94b 100644 --- a/Zotlabs/Lib/JcsEddsa2022.php +++ b/Zotlabs/Lib/JcsEddsa2022.php @@ -37,6 +37,7 @@ class JcsEddsa2022 { if (!str_starts_with($encodedSignature,'z')) { return false; } + $encodedSignature = substr($encodedSignature, 1); $optionsHash = $this->hash($this->signableOptions($data['proof']), true); $dataHash = $this->hash($this->signableData($data),true); @@ -58,7 +59,7 @@ class JcsEddsa2022 { $signableData = []; if ($data) { foreach ($data as $k => $v) { - if ($k != 'proof') { + if (!in_array($k, ['proof', 'signature'])) { $signableData[$k] = $v; } } -- cgit v1.2.3 From fadb0a5bf24199475f01f893c8892f5bba495bab Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 13 Jan 2024 20:45:32 +0000 Subject: check for assertionMethod --- Zotlabs/Lib/Activity.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 6c680c56e..3da6e6e92 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1757,12 +1757,14 @@ class Activity { } $epubkey = ''; - foreach($person_obj['assertionMethod'] as $am) { - if ($person_obj['id'] === $am['controller'] && - $am['type'] === 'Multikey' && - str_starts_with($am['publicKeyMultibase'], 'z6Mk') - ) { - $epubkey = $person_obj['assertionMethod']['publicKeyMultibase']; + if (isset($person_obj['assertionMethod'])) { + foreach($person_obj['assertionMethod'] as $am) { + if ($person_obj['id'] === $am['controller'] && + $am['type'] === 'Multikey' && + str_starts_with($am['publicKeyMultibase'], 'z6Mk') + ) { + $epubkey = $person_obj['assertionMethod']['publicKeyMultibase']; + } } } -- cgit v1.2.3 From 9d3b852d380760fa6e05491df1fd9b1e02fdf7d2 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 14 Jan 2024 08:10:27 +0000 Subject: fix wrong array key --- Zotlabs/Lib/Libzot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 41c091fb6..0d11704f1 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -777,7 +777,7 @@ class Libzot { intval($arr['public_forum']), dbesc(escape_tags($arr['primary_location']['address'])), dbesc(escape_tags($arr['primary_location']['url'])), - dbesc($arr['xchan_epubkey'] ?? ''), + dbesc($arr['ed25519_key'] ?? ''), dbesc($xchan_hash) ); -- cgit v1.2.3 From e078e133257aca1f1508382135ea342cc751c96d Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 14 Jan 2024 09:40:18 +0000 Subject: make sure we are dealing with an array --- Zotlabs/Lib/Activity.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 3da6e6e92..f59992cc3 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1758,6 +1758,10 @@ class Activity { $epubkey = ''; if (isset($person_obj['assertionMethod'])) { + if (!isset($person_obj['assertionMethod'][0])) { + $person_obj['assertionMethod'] = [$person_obj['assertionMethod']]; + } + foreach($person_obj['assertionMethod'] as $am) { if ($person_obj['id'] === $am['controller'] && $am['type'] === 'Multikey' && -- cgit v1.2.3 From 2bbecfe8dd44bd51a3425ee667859946f6ac0763 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 14 Jan 2024 10:11:20 +0000 Subject: only attempt fetch if zotfinger actually returned something --- Zotlabs/Lib/Activity.php | 2 +- Zotlabs/Lib/ActivityStreams.php | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index f59992cc3..f4c395906 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1767,7 +1767,7 @@ class Activity { $am['type'] === 'Multikey' && str_starts_with($am['publicKeyMultibase'], 'z6Mk') ) { - $epubkey = $person_obj['assertionMethod']['publicKeyMultibase']; + $epubkey = $am['publicKeyMultibase']; } } } diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index 98fc73462..f0fb7c9ae 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -327,9 +327,10 @@ class ActivityStreams { if ($x === null && strpos($url, '/channel/')) { // look for other nomadic channels which might be alive $zf = Zotfinger::exec($url, $channel); - - $url = $zf['signature']['signer']; - $x = Activity::fetch($url, $channel); + if ($zf) { + $url = $zf['signature']['signer']; + $x = Activity::fetch($url, $channel); + } } } -- cgit v1.2.3 From 03819abb22cd8f3c72eaa2b39f424249434f392a Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 14 Jan 2024 17:23:19 +0000 Subject: remove acct from webfinger --- Zotlabs/Lib/Activity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index f4c395906..ab5130ada 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1680,7 +1680,7 @@ class Activity { $name = t('Unknown'); } - $webfinger_addr = $person_obj['webfinger'] ?? ''; + $webfinger_addr = ((isset($person_obj['webfinger'])) ? str_replace('acct:', '', $person_obj['webfinger']) : ''); $hostname = ''; $baseurl = ''; $site_url = ''; -- cgit v1.2.3 From 9cc85adf4734aec5bdaf7057b5885849a40c4340 Mon Sep 17 00:00:00 2001 From: Mario Vavti Date: Fri, 19 Jan 2024 11:02:13 +0100 Subject: Fix regression in Activity::actor_store() --- Zotlabs/Lib/Activity.php | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index ab5130ada..61c36dc04 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1628,11 +1628,15 @@ class Activity { } */ - $url = null; - $ap_hubloc = null; + $url = $person_obj['id'] ?? ''; + + if (!$url) { + return; + } $hublocs = self::get_actor_hublocs($url); $has_zot_hubloc = false; + $ap_hubloc = null; if ($hublocs) { foreach ($hublocs as $hub) { @@ -1656,14 +1660,6 @@ class Activity { } } - if (isset($person_obj['id'])) { - $url = $person_obj['id']; - } - - if (!$url) { - return; - } - $inbox = $person_obj['inbox'] ?? null; // invalid AP identity -- cgit v1.2.3 From fa4ab45692e5deaee3a51408a43c00a834f99903 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 19 Jan 2024 20:10:50 +0000 Subject: native repeats continued --- Zotlabs/Lib/Activity.php | 42 +++++++++++++++++++++++++++++------------ Zotlabs/Lib/ActivityStreams.php | 2 +- Zotlabs/Lib/Enotify.php | 28 +++++++++------------------ Zotlabs/Lib/Libzot.php | 31 ++++++++++++++---------------- Zotlabs/Lib/ThreadItem.php | 39 +++++++++++++++++++++++++++++++++----- 5 files changed, 88 insertions(+), 54 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 61c36dc04..2bf8543b2 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -59,13 +59,16 @@ class Activity { "select *, id as item_id from item where mid = '%s' and item_wall = 1 $item_normal $sql_extra", dbesc($url) ); + if ($j) { xchan_query($j, true); $items = fetch_post_tags($j); } + if ($items) { return self::encode_item(array_shift($items), true); } + return null; } @@ -537,7 +540,7 @@ class Activity { } } - if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) { + if (intval($i['item_wall'])) { $ret['commentPolicy'] = map_scope(PermissionLimits::Get($i['uid'], 'post_comments')); } @@ -1586,8 +1589,7 @@ class Activity { } public static function drop($channel, $observer, $act) { - $r = q( - "select * from item where mid = '%s' and uid = %d limit 1", + $r = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc((is_array($act->obj)) ? $act->obj['id'] : $act->obj), intval($channel['channel_id']) ); @@ -1607,7 +1609,6 @@ class Activity { if ($r[0]['item_wall']) { Master::Summon(['Notifier', 'drop', $r[0]['id']]); } - } @@ -2431,6 +2432,10 @@ class Activity { } } + if ($act->type === 'Announce') { + $content['content'] = sprintf(t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']); + } + if ($act->type === 'emojiReaction') { $content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';'); } @@ -3034,7 +3039,7 @@ class Activity { // The $item['item_fetched'] flag is set in fetch_and_store_parents(). // In this case we should check against author permissions because sender is not owner. - if (perm_is_allowed($channel['channel_id'], ((!empty($item['item_fetched'])) ? $item['author_xchan'] : $observer_hash), 'send_stream') || $is_sys_channel) { + if (perm_is_allowed($channel['channel_id'], ((empty($item['item_fetched'])) ? $observer_hash : $item['author_xchan']), 'send_stream') || $is_sys_channel) { $allowed = true; } @@ -3162,6 +3167,10 @@ class Activity { $fetch = false; if (perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') || $is_sys_channel) { + if ($item['verb'] === 'Announce') { + $force = true; + } + $fetch = (($fetch_parents) ? self::fetch_and_store_parents($channel, $observer_hash, $item, $force) : false); } @@ -3178,6 +3187,7 @@ class Activity { return; } + $item['owner_xchan'] = (($item['verb'] === 'Announce') ? $parent[0]['author_xchan'] : $parent[0]['owner_xchan']); if ($parent[0]['parent_mid'] !== $item['parent_mid']) { $item['thr_parent'] = $item['parent_mid']; @@ -3236,12 +3246,6 @@ class Activity { intval($item['uid']) ); if ($r) { - - // If we already have the item, dismiss its announce - if ($act->type === 'Announce') { - return; - } - if ($item['edited'] > $r[0]['edited']) { $item['id'] = $r[0]['id']; $x = item_store_update($item); @@ -3307,6 +3311,8 @@ class Activity { $p = []; + $announce_init = $item['verb'] === 'Announce'; + $current_item = $item; while ($current_item['parent_mid'] !== $current_item['mid']) { @@ -3348,6 +3354,7 @@ class Activity { $item = $hookinfo['item']; if ($item) { + $item['item_fetched'] = true; if (intval($channel['channel_system']) && intval($item['item_private'])) { @@ -3360,9 +3367,19 @@ class Activity { break; } + if ($announce_init) { + // If the fetch was initiated by an announce activity + // do not set item fetched. This way the owner will be set to the + // observer -> the announce actor + unset($item['item_fetched']); + $item['verb'] = 'Announce'; + $item['parent_mid'] = $item['mid']; + $item['item_thread_top'] = 1; + } + array_unshift($p, [$a, $item]); - if ($item['parent_mid'] === $item['mid']) { + if ($announce_init || $item['parent_mid'] === $item['mid']) { break; } } @@ -3370,6 +3387,7 @@ class Activity { $current_item = $item; } + if ($p) { foreach ($p as $pv) { if ($pv[0]->is_valid()) { diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index f0fb7c9ae..0770f2040 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -345,7 +345,7 @@ class ActivityStreams { if (!$s) { return false; } - return (in_array($s, ['Like', 'Dislike', 'Flag', 'Block', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact'])); + return (in_array($s, ['Announce', 'Like', 'Dislike', 'Flag', 'Block', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact'])); } /** diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index c3f96e103..d8e6f575a 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -149,7 +149,7 @@ class Enotify { if(array_key_exists('item',$params)) { - if(in_array($params['item']['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) { + if(in_array($params['item']['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_SHARE])) { if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) { logger('notification: not a visible activity. Ignoring.'); @@ -163,6 +163,9 @@ class Enotify { if(activity_match($params['verb'], ACTIVITY_DISLIKE)) $action = (($moderated) ? t('requested to dislike') : t('disliked')); + if(activity_match($params['verb'], ACTIVITY_SHARE)) + $action = t('repeated'); + } if($params['item']['obj_type'] === 'Answer') @@ -835,18 +838,6 @@ class Enotify { : (($item['obj_type'] === 'Answer') ? sprintf( t('voted on %s\'s poll'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]') : sprintf( t('commented on %s\'s post'), '[bdi]' . $item['owner']['xchan_name'] . '[/bdi]')) ); - if($item['verb'] === ACTIVITY_SHARE && empty($item['owner']['xchan_pubforum'])) { - $itemem_text = sprintf( t('repeated %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]'); - } - - if($item['verb'] === ACTIVITY_LIKE) { - $itemem_text = sprintf( t('liked %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]'); - } - - if($item['verb'] === ACTIVITY_DISLIKE) { - $itemem_text = sprintf( t('disliked %s\'s post'), '[bdi]' . $item['author']['xchan_name'] . '[/bdi]'); - } - if(in_array($item['obj_type'], ['Document', 'Video', 'Audio', 'Image'])) { $itemem_text = t('shared a file with you'); } @@ -867,7 +858,6 @@ class Enotify { // convert this logic into a json array just like the system notifications - $who = (($item['verb'] === ACTIVITY_SHARE && empty($item['owner']['xchan_pubforum'])) ? 'owner' : 'author'); $body = html2plain(bbcode($item['body'], ['drop_media' => true, 'tryoembed' => false]), 75, true); if ($body) { $body = htmlentities($body, ENT_QUOTES, 'UTF-8', false); @@ -875,10 +865,10 @@ class Enotify { $x = array( 'notify_link' => $item['llink'], - 'name' => $item[$who]['xchan_name'], - 'addr' => $item[$who]['xchan_addr'] ? $item[$who]['xchan_addr'] : $item[$who]['xchan_url'], - 'url' => $item[$who]['xchan_url'], - 'photo' => $item[$who]['xchan_photo_s'], + 'name' => $item['author']['xchan_name'], + 'addr' => $item['author']['xchan_addr'] ? $item['author']['xchan_addr'] : $item['author']['xchan_url'], + 'url' => $item['author']['xchan_url'], + 'photo' => $item['author']['xchan_photo_s'], 'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])), 'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'), 'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''), @@ -887,7 +877,7 @@ class Enotify { 'message' => bbcode(escape_tags($itemem_text)), 'body' => $body, // these are for the superblock addon - 'hash' => $item[$who]['xchan_hash'], + 'hash' => $item['author']['xchan_hash'], 'uid' => $item['uid'], 'display' => true ); diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 0d11704f1..be1ca15c0 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1204,7 +1204,6 @@ class Libzot { // @fixme; $deliveries = self::public_recips($env, $AS); - } $deliveries = array_unique($deliveries); @@ -1225,10 +1224,6 @@ class Libzot { $author_url = $AS->actor['id']; - if ($AS->type === 'Announce') { - $author_url = Activity::get_attributed_to_actor_url($AS); - } - $r = Activity::get_actor_hublocs($author_url); if (!$r) { @@ -1650,9 +1645,12 @@ class Libzot { } } - } elseif ($permit_mentions) { + } + elseif ($permit_mentions) { $allowed = true; } + + } if ($request) { @@ -1731,11 +1729,15 @@ class Libzot { // the top level post is unlikely to be imported and // this is just an exercise in futility. - if (perm_is_allowed($channel['channel_id'], $sender, 'send_stream')) { - Master::Summon(['Zotconvo', $channel['channel_id'], $arr['parent_mid']]); + if ($arr['verb'] === 'Announce') { + Activity::fetch_and_store_parents($channel, $sender, $arr, true); + } + else { + if (perm_is_allowed($channel['channel_id'], $sender, 'send_stream')) { + Master::Summon(['Zotconvo', $channel['channel_id'], $arr['parent_mid']]); + } + continue; } - - continue; } if ($r[0]['obj_type'] === 'Question') { @@ -1758,6 +1760,8 @@ class Libzot { // so just set the owner and route accordingly. $arr['route'] = $r[0]['route']; $arr['owner_xchan'] = $r[0]['owner_xchan']; + + } else { @@ -1841,13 +1845,6 @@ class Libzot { ); if ($r) { - // We already have this post. - // Dismiss its announce - if ($act->type === 'Announce') { - $DR->update('update ignored'); - $result[] = $DR->get(); - continue; - } $item_id = $r[0]['id']; diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 3cdb59e5f..e7d6e33f8 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -196,9 +196,14 @@ class ThreadItem { $attend = null; // process action responses - e.g. like/dislike/attend/agree/whatever - $response_verbs = array('like'); - if(feature_enabled($conv->get_profile_owner(),'dislike')) + $response_verbs[] = 'like'; + + if(feature_enabled($conv->get_profile_owner(),'dislike')) { $response_verbs[] = 'dislike'; + } + + $response_verbs[] = 'announce'; + if(in_array($item['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) { $response_verbs[] = 'attendyes'; $response_verbs[] = 'attendno'; @@ -224,6 +229,8 @@ class ThreadItem { $my_responses[$v] = ((isset($conv_responses[$v][$item['mid'] . '-m'])) ? 1 : 0); } +/* + $like_count = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid']] : ''); $like_list = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid'] . '-l'] : ''); if (($like_list) && (count($like_list) > MAX_LIKERS)) { @@ -234,6 +241,16 @@ class ThreadItem { } $like_button_label = tt('Like','Likes',$like_count,'noun'); + $repeat_count = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid']] : ''); + $repeat_list = ((x($conv_responses['announce'],$item['mid'])) ? $conv_responses['announce'][$item['mid'] . '-l'] : ''); + if (($repeat_list) && (count($repeat_list) > MAX_LIKERS)) { + $repeat_list_part = array_slice($repeat_list, 0, MAX_LIKERS); + array_push($repeat_list_part, '' . t('View all') . ''); + } else { + $repeat_list_part = ''; + } + $repeat_button_label = tt('Repeat','Repeats',$repeat_count,'noun'); + $showdislike = ''; if (feature_enabled($conv->get_profile_owner(),'dislike')) { $dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : ''); @@ -250,6 +267,7 @@ class ThreadItem { } $showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : ''); +*/ /* * We should avoid doing this all the time, but it depends on the conversation mode @@ -483,19 +501,29 @@ class ThreadItem { 'markseen' => t('Mark all seen'), 'responses' => $responses, 'my_responses' => $my_responses, + /* 'like_count' => $like_count, 'like_list' => $like_list, 'like_list_part' => $like_list_part, 'like_button_label' => $like_button_label, 'like_modal_title' => t('Likes','noun'), + + 'repeat_count' => $repeat_count, + 'repeat_list' => $repeat_list, + 'repeat_list_part' => $repeat_list_part, + 'repeat_button_label' => $repeat_button_label, + 'repeat_modal_title' => t('Repeats','noun'), + + 'dislike_modal_title' => t('Dislikes','noun'), 'dislike_count' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_count : ''), 'dislike_list' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list : ''), 'dislike_list_part' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list_part : ''), 'dislike_button_label' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_button_label : ''), +*/ 'modal_dismiss' => t('Close'), - 'showlike' => $showlike, - 'showdislike' => $showdislike, + // 'showlike' => $showlike, + // 'showdislike' => $showdislike, 'comment' => ($item['item_delayed'] ? '' : $this->get_comment_box()), 'previewing' => ($conv->is_preview() ? true : false ), 'preview_lbl' => t('This is an unsaved preview'), @@ -507,7 +535,8 @@ class ThreadItem { 'moderate' => ($item['item_blocked'] == ITEM_MODERATED), 'moderate_approve' => t('Approve'), 'moderate_delete' => t('Delete'), - 'rtl' => in_array($item['lang'], rtl_languages()) + 'rtl' => in_array($item['lang'], rtl_languages()), + ); -- cgit v1.2.3 From b0664f7349c60183f0cb9597bd02b741d3c165c8 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 22 Jan 2024 09:09:41 +0000 Subject: store the original announce actor (the one that pushed the item into our stream first) in source_xchan instead of owner_xchan. this way we will preserve the real owner for the thread and not have conflicts when dealing with deletes of comments or likes --- Zotlabs/Lib/Activity.php | 8 +++----- Zotlabs/Lib/ThreadItem.php | 6 ++++++ 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 2bf8543b2..1f36177bd 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3368,12 +3368,10 @@ class Activity { } if ($announce_init) { - // If the fetch was initiated by an announce activity - // do not set item fetched. This way the owner will be set to the - // observer -> the announce actor - unset($item['item_fetched']); + // Store the sender of the initial announce + $item['source_xchan'] = $observer_hash; $item['verb'] = 'Announce'; - $item['parent_mid'] = $item['mid']; + $item['parent_mid'] = $item['thr_parent'] = $item['mid']; $item['item_thread_top'] = 1; } diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index e7d6e33f8..77f26c386 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -907,6 +907,12 @@ class ThreadItem { $this->owner_name = $this->data['owner']['xchan_name']; $this->wall_to_wall = true; } + elseif($this->is_toplevel() && $this->get_data_value('verb') === 'Announce' && isset($this->data['source'])) { + $this->owner_url = chanlink_hash($this->data['source']['xchan_hash']); + $this->owner_photo = $this->data['source']['xchan_photo_s']; + $this->owner_name = $this->data['source']['xchan_name']; + $this->wall_to_wall = true; + } } private function is_wall_to_wall() { -- cgit v1.2.3 From 651a28814815196c1aed2d6bc1adb99fd642c6f0 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 22 Jan 2024 09:17:55 +0000 Subject: set item_uplink to 0 just to be sure (this should not be necessary) --- Zotlabs/Lib/Activity.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 1f36177bd..cf0cf8734 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3370,6 +3370,8 @@ class Activity { if ($announce_init) { // Store the sender of the initial announce $item['source_xchan'] = $observer_hash; + // WARNING: the presence of both source_xchan and non-zero item_uplink here will cause a delivery loop + $item['item_uplink'] = 0; $item['verb'] = 'Announce'; $item['parent_mid'] = $item['thr_parent'] = $item['mid']; $item['item_thread_top'] = 1; -- cgit v1.2.3 From 9449e8bd61a57651a19838467f8d3350f26e9a91 Mon Sep 17 00:00:00 2001 From: Mario Vavti Date: Wed, 24 Jan 2024 16:40:05 +0100 Subject: fix issue where if an item is created and deleted again before the notifier has completed the queueworker will dismiss the delete because it looks like a duplicate entry --- Zotlabs/Lib/Libzot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index be1ca15c0..b8067bc56 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1827,7 +1827,7 @@ class Libzot { if ($relay && $item_id) { logger('process_delivery: invoking relay'); - Master::Summon(['Notifier', 'relay', intval($item_id)]); + Master::Summon(['Notifier', 'relay', intval($item_id), 'delete']); $DR->update('relayed'); $result[] = $DR->get(); } -- cgit v1.2.3 From e513950cb5a16a996b60335716e101663dfa6393 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 24 Jan 2024 16:44:42 +0000 Subject: restructure Libzot::process_delivery() --- Zotlabs/Lib/Libzot.php | 312 +++++++++++++++++++++++++------------------------ 1 file changed, 160 insertions(+), 152 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index b8067bc56..265bcb376 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1157,7 +1157,6 @@ class Libzot { else { $item = []; } - logger($AS->debug(), LOGGER_DATA); } @@ -1364,11 +1363,13 @@ class Libzot { static function find_parent_owner_hashes($env, $act) { $r = []; - $thread_parent = self::find_parent($env, $act); - if ($thread_parent) { - $uids = q("SELECT uid FROM item WHERE thr_parent = '%s' OR parent_mid = '%s'", - dbesc($thread_parent), - dbesc($thread_parent) + $parent = self::find_parent($env, $act); + + if ($parent) { + $uids = q("SELECT uid FROM item WHERE thr_parent = '%s' OR parent_mid = '%s' OR mid = '%s'", + dbesc($parent), + dbesc($parent), + dbesc($parent) ); if ($uids) { @@ -1579,6 +1580,39 @@ class Libzot { continue; } + $arr['item_wall'] = 0; + + // This is our own post, possibly coming from a channel clone + if ($arr['owner_xchan'] === $d) { + $arr['item_wall'] = 1; + } + + if (isset($arr['item_deleted']) && $arr['item_deleted']) { + + // remove_community_tag is a no-op if this isn't a community tag activity + // self::remove_community_tag($sender, $arr, $channel['channel_id']); + + // set these just in case we need to store a fresh copy of the deleted post. + // This could happen if the delete got here before the original post did. + + $arr['aid'] = $channel['channel_account_id']; + $arr['uid'] = $channel['channel_id']; + + $item_id = self::delete_imported_item($sender, $act, $arr, $channel['channel_id'], $relay); + $DR->update(($item_id) ? 'deleted' : 'delete_failed'); + $result[] = $DR->get(); + + if ($relay && $item_id) { + logger('process_delivery: invoking relay'); + Master::Summon(['Notifier', 'relay', intval($item_id), 'delete']); + $DR->update('relayed'); + $result[] = $DR->get(); + } + + continue; + } + + // allow public postings to the sys channel regardless of permissions, but not // for comments travelling upstream. Wait and catch them on the way down. // They may have been blocked by the owner. @@ -1605,119 +1639,23 @@ class Libzot { } $tag_delivery = tgroup_check($channel['channel_id'], $arr); - $perm = 'send_stream'; - if (($arr['mid'] !== $arr['parent_mid']) && ($relay)) - $perm = 'post_comments'; - - // This is our own post, possibly coming from a channel clone - - if ($arr['owner_xchan'] == $d) { - $arr['item_wall'] = 1; - } - else { - $arr['item_wall'] = 0; - } - - $friendofriend = false; - - if ((!$tag_delivery) && (!$local_public)) { - $allowed = (perm_is_allowed($channel['channel_id'], $sender, $perm)); - - $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system', 'permit_all_mentions') && i_am_mentioned($channel, $arr)); - - if (!$allowed) { - if ($perm === 'post_comments') { - $parent = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($arr['parent_mid']), - intval($channel['channel_id']) - ); - if ($parent) { - $allowed = can_comment_on_post($sender, $parent[0]); - if (!$allowed && $permit_mentions) { - $allowed = true; - } - - if (!$allowed) { - if (PConfig::Get($channel['channel_id'], 'system', 'moderate_unsolicited_comments') && $arr['obj_type'] !== 'Answer') { - $arr['item_blocked'] = ITEM_MODERATED; - $allowed = true; - } - } - } - } - elseif ($permit_mentions) { - $allowed = true; - } - - - } - - if ($request) { - // Conversation fetches (e.g. $request == true) take place for - // a) new comments on expired posts - // b) hyperdrive (friend-of-friend) conversations - // c) Repeats of posts by others - - - // over-ride normal connection permissions for hyperdrive (friend-of-friend) conversations - // (if hyperdrive is enabled) and repeated posts by a friend. - // If $allowed is already true, this is probably the conversation of a direct friend or a - // conversation fetch for a new comment on an expired post - // Comments of all these activities are allowed and will only be rejected (later) if the parent - // doesn't exist. - - if ($perm === 'send_stream') { - if ($force || get_pconfig($channel['channel_id'], 'system', 'hyperdrive', false)) { - $allowed = true; - } - } - else { - $allowed = true; - } - - $friendofriend = true; - } - - if (intval($arr['item_private']) === 2) { - if (!perm_is_allowed($channel['channel_id'], $sender, 'post_mail')) { - $allowed = false; - } - } - - if (!$allowed) { - logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); - $DR->update('permission denied'); - $result[] = $DR->get(); - continue; - } - } - - // logger('item: ' . print_r($arr,true), LOGGER_DATA); + $perm = 'send_stream'; if ($arr['mid'] !== $arr['parent_mid']) { - logger('checking source: "' . $arr['mid'] . '" != "' . $arr['parent_mid'] . '"'); + if ($relay) + $perm = 'post_comments'; - // check source route. - // We are only going to accept comments from this sender if the comment has the same route as the top-level-post, - // this is so that permissions mismatches between senders apply to the entire conversation - // As a side effect we will also do a preliminary check that we have the top-level-post, otherwise - // processing it is pointless. - - $r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1", + $parent = q("select * from item where mid = '%s' and uid = %d limit 1", dbesc($arr['parent_mid']), intval($channel['channel_id']) ); - if (!$r) { + if (!$parent) { $DR->update('comment parent not found'); $result[] = $DR->get(); - if ($relay || $request || $local_public) { - continue; - } - // We don't seem to have a copy of this conversation or at least the parent // - so request a copy of the entire conversation to date. // Don't do this if it's a relay post as we're the ones who are supposed to @@ -1729,28 +1667,49 @@ class Libzot { // the top level post is unlikely to be imported and // this is just an exercise in futility. + if ($relay || $request || $local_public || !perm_is_allowed($channel['channel_id'], $sender, 'send_stream')) { + continue; + } + if ($arr['verb'] === 'Announce') { - Activity::fetch_and_store_parents($channel, $sender, $arr, true); + + // TODO: move this to background + + if (!Activity::fetch_and_store_parents($channel, $sender, $arr, true)) { + continue; + } + + $parent = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($arr['parent_mid']), + intval($channel['channel_id']) + ); + } else { - if (perm_is_allowed($channel['channel_id'], $sender, 'send_stream')) { - Master::Summon(['Zotconvo', $channel['channel_id'], $arr['parent_mid']]); - } + Master::Summon(['Zotconvo', $channel['channel_id'], $arr['parent_mid']]); continue; } + } - if ($r[0]['obj_type'] === 'Question') { + logger('checking source: "' . $arr['mid'] . '" != "' . $arr['parent_mid'] . '"'); + + // check source route. + // We are only going to accept comments from this sender if the comment has the same route as the top-level-post, + // this is so that permissions mismatches between senders apply to the entire conversation + // As a side effect we will also do a preliminary check that we have the top-level-post, otherwise + // processing it is pointless. + + if ($parent[0]['obj_type'] === 'Question') { // route checking doesn't work correctly here because we've changed the privacy - $r[0]['route'] = EMPTY_STR; + $parent[0]['route'] = EMPTY_STR; // If this is a poll response, convert the obj_type to our (internal-only) "Answer" type if ($arr['obj_type'] === ACTIVITY_OBJ_COMMENT && $arr['title'] && (!$arr['body'])) { $arr['obj_type'] = 'Answer'; } } - - if ($relay || $friendofriend || (intval($r[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) { + if ($relay || (intval($parent[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) { // reset the route in case it travelled a great distance upstream // use our parent's route so when we go back downstream we'll match // with whatever route our parent has. @@ -1758,10 +1717,8 @@ class Libzot { // but we are now getting comments via listener delivery // and if there is no privacy on this or the parent, we don't care about the route, // so just set the owner and route accordingly. - $arr['route'] = $r[0]['route']; - $arr['owner_xchan'] = $r[0]['owner_xchan']; - - + $arr['route'] = $parent[0]['route']; + $arr['owner_xchan'] = $parent[0]['owner_xchan']; } else { @@ -1771,7 +1728,7 @@ class Libzot { // only compare the last hop since it could have arrived at the last location any number of ways. // Always accept empty routes and firehose items (route contains 'undefined') . - $existing_route = explode(',', $r[0]['route']); + $existing_route = explode(',', $parent[0]['route']); $routes = count($existing_route); if ($routes) { $last_hop = array_pop($existing_route); @@ -1788,8 +1745,8 @@ class Libzot { $current_route = ((isset($arr['route']) && $arr['route']) ? $arr['route'] . ',' : '') . $sender; if ($last_hop && $last_hop != $sender) { - logger('comment route mismatch: parent route = ' . $r[0]['route'] . ' expected = ' . $current_route, LOGGER_DEBUG); - logger('comment route mismatch: parent msg = ' . $r[0]['id'], LOGGER_DEBUG); + logger('comment route mismatch: parent route = ' . $parent[0]['route'] . ' expected = ' . $current_route, LOGGER_DEBUG); + logger('comment route mismatch: parent msg = ' . $parent[0]['id'], LOGGER_DEBUG); $DR->update('comment route mismatch'); $result[] = $DR->get(); continue; @@ -1802,42 +1759,86 @@ class Libzot { } } - // 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' )", - intval($channel['channel_id']), - dbesc($arr['owner_xchan']), - dbesc($arr['author_xchan']) - ); + if (!$tag_delivery && !$local_public) { + $allowed = (perm_is_allowed($channel['channel_id'], $sender, $perm)); - if (isset($arr['item_deleted']) && $arr['item_deleted']) { + $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system', 'permit_all_mentions') && i_am_mentioned($channel, $arr)); - // remove_community_tag is a no-op if this isn't a community tag activity - self::remove_community_tag($sender, $arr, $channel['channel_id']); + if (!$allowed) { + if ($parent && $perm === 'send_stream') { + // if we own the parent we will accept its comments + $allowed = true; + } - // set these just in case we need to store a fresh copy of the deleted post. - // This could happen if the delete got here before the original post did. + elseif ($parent && $perm === 'post_comments') { + $allowed = can_comment_on_post($sender, $parent[0]); - $arr['aid'] = $channel['channel_account_id']; - $arr['uid'] = $channel['channel_id']; + if (!$allowed && $permit_mentions) { + $allowed = true; + } + + if (!$allowed) { + if (PConfig::Get($channel['channel_id'], 'system', 'moderate_unsolicited_comments') && $arr['obj_type'] !== 'Answer') { + $arr['item_blocked'] = ITEM_MODERATED; + $allowed = true; + } + } + + } + elseif ($permit_mentions) { + $allowed = true; + } - $item_id = self::delete_imported_item($sender, $act, $arr, $channel['channel_id'], $relay); - $DR->update(($item_id) ? 'deleted' : 'delete_failed'); - $result[] = $DR->get(); - if ($relay && $item_id) { - logger('process_delivery: invoking relay'); - Master::Summon(['Notifier', 'relay', intval($item_id), 'delete']); - $DR->update('relayed'); - $result[] = $DR->get(); } - continue; + if ($request) { + // Conversation fetches (e.g. $request == true) take place for + // a) new comments on expired posts + // b) if we received an announce + + + // over-ride normal connection permissions for hyperdrive (friend-of-friend) conversations + // (if hyperdrive is enabled) and repeated posts by a friend. + // If $allowed is already true, this is probably the conversation of a direct friend or a + // conversation fetch for a new comment on an expired post + // Comments of all these activities are allowed and will only be rejected (later) if the parent + // doesn't exist. + + if ($perm === 'send_stream') { + if ($force) { + $allowed = true; + } + } + else { + $allowed = true; + } + } + + if (intval($arr['item_private']) === 2) { + if (!perm_is_allowed($channel['channel_id'], $sender, 'post_mail')) { + $allowed = false; + } + } + + if (!$allowed) { + logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); + $DR->update('permission denied'); + $result[] = $DR->get(); + continue; + } } + // 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' )", + intval($channel['channel_id']), + dbesc($arr['owner_xchan']), + dbesc($arr['author_xchan']) + ); + // reactions such as like and dislike could have an mid with /activity/ in it. // Check for both forms in order to prevent duplicates. - $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'])), @@ -1845,7 +1846,6 @@ class Libzot { ); if ($r) { - $item_id = $r[0]['id']; if (intval($r[0]['item_deleted'])) { @@ -1915,7 +1915,6 @@ class Libzot { if (post_is_importable($arr['uid'], $arr, $abook)) { $item_result = item_store($arr); if ($item_result['success']) { - $item_id = $item_result['item_id']; if ($item_source && in_array($item_result['item']['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) { @@ -1957,6 +1956,7 @@ class Libzot { // preserve conversations with which you are involved from expiration $stored = ((isset($item_result['item'])) ? $item_result['item'] : false); + if ((is_array($stored)) && ($stored['id'] != $stored['parent']) && ($stored['author_xchan'] === $channel['channel_hash'])) { retain_item($stored['item']['parent']); @@ -2320,12 +2320,20 @@ class Libzot { // this information from the metadata should have no other discernible impact. if (($stored['id'] != $stored['parent']) && intval($stored['item_origin'])) { - q("update item set item_origin = 0 where id = %d and uid = %d", - intval($stored['id']), - intval($stored['uid']) + q("update item set item_origin = 0 where id = %d", + intval($stored['id']) ); } - } + } else { + if ($stored['id'] !== $stored['parent']) { + q( + "update item set commented = '%s', changed = '%s' where id = %d", + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($stored['parent']) + ); + } + } // Use phased deletion to set the deleted flag, call both tag_deliver and the notifier to notify downstream channels -- cgit v1.2.3 From c0a7dfe2f6554fc66e753c456551dd580c479820 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 25 Jan 2024 10:13:10 +0000 Subject: refactor fetch_and_store_parents() and inroduce the fetchparents daemon --- Zotlabs/Lib/Activity.php | 531 ++++++----------------------------------------- Zotlabs/Lib/Libzot.php | 15 +- 2 files changed, 68 insertions(+), 478 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index cf0cf8734..c2049bb7b 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1869,31 +1869,6 @@ class Activity { } } - static function create_action($channel, $observer_hash, $act) { - - if (in_array($act->obj['type'], ['Note', 'Article', 'Video'])) { - self::create_note($channel, $observer_hash, $act); - } - - - } - - static function announce_action($channel, $observer_hash, $act) { - - if (in_array($act->type, ['Announce'])) { - self::announce_note($channel, $observer_hash, $act); - } - - } - - static function like_action($channel, $observer_hash, $act) { - - if (in_array($act->obj['type'], ['Note', 'Article', 'Video'])) { - self::like_note($channel, $observer_hash, $act); - } - - - } // sort function width decreasing static function vid_sort($a, $b) { @@ -2965,6 +2940,24 @@ class Activity { intval($channel['channel_id']) ); + if (!$parent) { + if (perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') || $is_sys_channel) { + if ($item['verb'] === 'Announce') { + $force = true; + } + + if ($fetch_parents) { + Master::Summon(['Fetchparents', $channel['channel_id'], $observer_hash, $item['mid'], $force]); + //self::fetch_and_store_parents($channel, $observer_hash, $item, $act, $force); + return; + } + + logger('no parent'); + return; + } + } + + // TODO: if we do not have a parent stop here and move the fetch to background? if ($parent && $parent[0]['obj_type'] === 'Question') { @@ -3159,35 +3152,8 @@ class Activity { } if ($is_child_node) { - if (!$parent) { - if (!plugin_is_installed('pubcrawl')) { - return; - } - - $fetch = false; - - if (perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') || $is_sys_channel) { - if ($item['verb'] === 'Announce') { - $force = true; - } - - $fetch = (($fetch_parents) ? self::fetch_and_store_parents($channel, $observer_hash, $item, $force) : false); - } - if ($fetch) { - $parent = q("select * from item where mid = '%s' and uid = %d", - dbesc($item['parent_mid']), - intval($item['uid']) - ); - } - } - - if (!$parent) { - logger('no parent'); - return; - } - - $item['owner_xchan'] = (($item['verb'] === 'Announce') ? $parent[0]['author_xchan'] : $parent[0]['owner_xchan']); + $item['owner_xchan'] = $parent[0]['owner_xchan']; if ($parent[0]['parent_mid'] !== $item['parent_mid']) { $item['thr_parent'] = $item['parent_mid']; @@ -3306,15 +3272,44 @@ class Activity { } - static public function fetch_and_store_parents($channel, $observer_hash, $item, $force = false) { + /** + * @brief fetch a thread upwards by either providing a message id or an item/activity pair + * + * @param array $channel + * @param array $observer_hash + * @param array $item string|array + * @param object $act activitystreams object (optional) default null + * @param bool $force disregard permissions and force storage (optional) default false + * @return bool + */ + + static public function fetch_and_store_parents($channel, $observer_hash, $item, $act = null, $force = false) { logger('fetching parents'); + if (!$item) { + return false; + } + $p = []; + $announce_init = false; + + if (is_object($act) && is_array($item)) { + $p[] = [$act, $item]; + $announce_init = ($item['verb'] === 'Announce'); + } - $announce_init = $item['verb'] === 'Announce'; + if (is_string($item)) { + $mid = $item; + $item = [ + 'parent_mid' => $mid, + 'mid' => '' + ]; + } $current_item = $item; + $i = 0; + while ($current_item['parent_mid'] !== $current_item['mid']) { $n = self::fetch($current_item['parent_mid'], $channel); @@ -3357,16 +3352,6 @@ class Activity { $item['item_fetched'] = true; - if (intval($channel['channel_system']) && intval($item['item_private'])) { - $p = []; - break; - } - - if (count($p) > 100) { - $p = []; - break; - } - if ($announce_init) { // Store the sender of the initial announce $item['source_xchan'] = $observer_hash; @@ -3376,427 +3361,43 @@ class Activity { $item['parent_mid'] = $item['thr_parent'] = $item['mid']; $item['item_thread_top'] = 1; } - - array_unshift($p, [$a, $item]); - - if ($announce_init || $item['parent_mid'] === $item['mid']) { - break; - } - } - - $current_item = $item; - } - - - if ($p) { - foreach ($p as $pv) { - if ($pv[0]->is_valid()) { - Activity::store($channel, $observer_hash, $pv[0], $pv[1], false, $force); + else { + $announce_init = ($i === 0 && $item['verb'] === 'Announce'); } - } - return true; - } - - return false; - } - /* - static public function fetch_and_store_parents($channel, $item) { - - logger('fetching parents'); - - $p = []; - - $current_item = $item; - - while ($current_item['parent_mid'] !== $current_item['mid']) { - $n = self::fetch($current_item['parent_mid'], $channel); - if (!$n) { + if (intval($channel['channel_system']) && intval($item['item_private'])) { + $p = []; break; } - $a = new ActivityStreams($n); - - //logger($a->debug()); - if (!$a->is_valid()) { + if (count($p) > 100) { + $p = []; break; } - if (is_array($a->actor) && array_key_exists('id', $a->actor)) { - self::actor_store($a->actor); - } - - $replies = null; - if (isset($a->obj['replies']['first']['items'])) { - $replies = $a->obj['replies']['first']['items']; - // we already have this one - array_diff($replies, [$current_item['mid']]); - } - - $item = null; - - switch ($a->type) { - case 'Create': - case 'Update': - //case 'Like': - //case 'Dislike': - case 'Announce': - $item = self::decode_note($a); - break; - default: - break; - - } - - $hookinfo = [ - 'a' => $a, - 'item' => $item - ]; - - call_hooks('fetch_and_store', $hookinfo); - - $item = $hookinfo['item']; - - if ($item) { - - array_unshift($p, [$a, $item, $replies]); - - if ($item['parent_mid'] === $item['mid'] || count($p) > 20) { - break; - } - - } - $current_item = $item; - } - - if ($p) { - foreach ($p as $pv) { - self::store($channel, $pv[0]->actor['id'], $pv[0], $pv[1], false); - if ($pv[2]) - self::fetch_and_store_replies($channel, $pv[2]); - } - return true; - } - - return false; - } - - static public function fetch_and_store_replies($channel, $arr) { - - logger('fetching replies'); - logger(print_r($arr, true)); - - $p = []; - - foreach ($arr as $url) { - - $n = self::fetch($url, $channel); - if (!$n) { - break; - } - - $a = new ActivityStreams($n); - - if (!$a->is_valid()) { - break; - } - - $item = null; + array_unshift($p, [$a, $item]); - switch ($a->type) { - case 'Create': - case 'Update': - case 'Like': - case 'Dislike': - case 'Announce': - $item = self::decode_note($a); - break; - default: + if ($item['parent_mid'] === $item['mid']) { break; - } - - $hookinfo = [ - 'a' => $a, - 'item' => $item - ]; - - call_hooks('fetch_and_store', $hookinfo); - - $item = $hookinfo['item']; + } - if ($item) { - array_unshift($p, [$a, $item]); } + $current_item = $item; + $i++; } if ($p) { foreach ($p as $pv) { - self::store($channel, $pv[0]->actor['id'], $pv[0], $pv[1], false); - } - } - - } -*/ - -/* this is deprecated and not used anymore - static function announce_note($channel, $observer_hash, $act) { - - $s = []; - $is_sys_channel = is_sys_channel($channel['channel_id']); - - if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') && !$is_sys_channel) { - logger('no permission'); - return; - } - - $content = self::get_content($act->obj); - - if (!$content) { - logger('no content'); - return; - } - - $s['owner_xchan'] = $s['author_xchan'] = $observer_hash; - - $s['aid'] = $channel['channel_account_id']; - $s['uid'] = $channel['channel_id']; - $s['mid'] = urldecode($act->obj['id']); - $s['plink'] = urldecode($act->obj['id']); - - if (!$s['created']) - $s['created'] = datetime_convert(); - - if (!$s['edited']) - $s['edited'] = $s['created']; - - - $s['parent_mid'] = $s['mid']; - - $s['verb'] = ACTIVITY_POST; - $s['obj_type'] = ACTIVITY_OBJ_NOTE; - $s['app'] = t('ActivityPub'); - - if ($channel['channel_system']) { - if (!MessageFilter::evaluate($s, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { - logger('post is filtered'); - return; - } - } - - $abook = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($observer_hash), - intval($channel['channel_id']) - ); - - if ($abook) { - if (!post_is_importable($s, $abook[0])) { - logger('post is filtered'); - return; - } - } - - if ($act->obj['conversation']) { - set_iconfig($s, 'ostatus', 'conversation', $act->obj['conversation'], 1); - } - - $a = self::decode_taxonomy($act->obj); - if ($a) { - $s['term'] = $a; - } - - $a = self::decode_attachment($act->obj); - if ($a) { - $s['attach'] = $a; - } - - $body = "[share author='" . urlencode($act->sharee['name']) . - "' profile='" . $act->sharee['url'] . - "' avatar='" . $act->sharee['photo_s'] . - "' link='" . ((is_array($act->obj['url'])) ? $act->obj['url']['href'] : $act->obj['url']) . - "' auth='" . ((is_matrix_url($act->obj['url'])) ? 'true' : 'false') . - "' posted='" . $act->obj['published'] . - "' message_id='" . $act->obj['id'] . - "']"; - - if ($content['name']) - $body .= self::bb_content($content, 'name') . "\r\n"; - - $body .= self::bb_content($content, 'content'); - - if ($act->obj['type'] === 'Note' && $s['attach']) { - $body .= self::bb_attach($s['attach'], $body); - } - - $body .= "[/share]"; - - $s['title'] = self::bb_content($content, 'name'); - $s['body'] = $body; - - if ($act->recips && (!in_array(ACTIVITY_PUBLIC_INBOX, $act->recips))) - $s['item_private'] = 1; - - set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); - - $r = q("select created, edited from item where mid = '%s' and uid = %d limit 1", - dbesc($s['mid']), - intval($s['uid']) - ); - if ($r) { - if ($s['edited'] > $r[0]['edited']) { - $x = item_store_update($s); - } - else { - return; - } - } - else { - $x = item_store($s); - } - - if (is_array($x) && $x['item_id']) { - if ($s['owner_xchan'] === $channel['channel_hash']) { - // We are the owner of this conversation, so send all received comments back downstream - Master::Summon(['Notifier', 'comment-import', $x['item_id']]); - } - $r = q("select * from item where id = %d limit 1", - intval($x['item_id']) - ); - if ($r) { - send_status_notifications($x['item_id'], $r[0]); + if ($pv[0]->is_valid()) { + Activity::store($channel, $observer_hash, $pv[0], $pv[1], false, $force); + } } - - sync_an_item($channel['channel_id'], $x['item_id']); + return true; } - + return false; } -*/ - - static function like_note($channel, $observer_hash, $act) { - - $s = []; - - $parent = $act->obj['id']; - - if ($act->type === 'Like') - $s['verb'] = ACTIVITY_LIKE; - if ($act->type === 'Dislike') - $s['verb'] = ACTIVITY_DISLIKE; - - if (!$parent) - return; - - $r = q("select * from item where uid = %d and ( mid = '%s' or mid = '%s' ) limit 1", - intval($channel['channel_id']), - dbesc($parent), - dbesc(urldecode(basename($parent))) - ); - - if (!$r) { - logger('parent not found.'); - return; - } - - xchan_query($r); - $parent_item = $r[0]; - if ($parent_item['owner_xchan'] === $channel['channel_hash']) { - if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'post_comments')) { - logger('no comment permission.'); - return; - } - } - - if ($parent_item['mid'] === $parent_item['parent_mid']) { - $s['parent_mid'] = $parent_item['mid']; - } - else { - $s['thr_parent'] = $parent_item['mid']; - $s['parent_mid'] = $parent_item['parent_mid']; - } - - $s['owner_xchan'] = $parent_item['owner_xchan']; - $s['author_xchan'] = $observer_hash; - - $s['aid'] = $channel['channel_account_id']; - $s['uid'] = $channel['channel_id']; - $s['mid'] = $act->id; - - if (!$s['parent_mid']) - $s['parent_mid'] = $s['mid']; - - - $post_type = (($parent_item['resource_type'] === 'photo') ? t('photo') : t('post')); - - $links = [['rel' => 'alternate', 'type' => 'text/html', 'href' => $parent_item['plink']]]; - $objtype = (($parent_item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE); - - $z = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($parent_item['author_xchan']) - ); - if ($z) - $item_author = $z[0]; - - $object = json_encode([ - 'type' => $post_type, - 'id' => $parent_item['mid'], - 'parent' => (($parent_item['thr_parent']) ? $parent_item['thr_parent'] : $parent_item['parent_mid']), - 'link' => $links, - 'title' => $parent_item['title'], - 'content' => $parent_item['body'], - 'created' => $parent_item['created'], - 'edited' => $parent_item['edited'], - 'author' => [ - 'name' => $item_author['xchan_name'], - 'address' => $item_author['xchan_addr'], - 'guid' => $item_author['xchan_guid'], - 'guid_sig' => $item_author['xchan_guid_sig'], - 'link' => [ - ['rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']], - ['rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m']]], - ], - ], JSON_UNESCAPED_SLASHES - ); - - if ($act->type === 'Like') - $bodyverb = t('%1$s likes %2$s\'s %3$s'); - if ($act->type === 'Dislike') - $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); - - $ulink = '[url=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/url]'; - $alink = '[url=' . $parent_item['author']['xchan_url'] . ']' . $parent_item['author']['xchan_name'] . '[/url]'; - $plink = '[url=' . z_root() . '/display/' . urlencode($act->id) . ']' . $post_type . '[/url]'; - $s['body'] = sprintf($bodyverb, $ulink, $alink, $plink); - - $s['app'] = t('ActivityPub'); - - // set the route to that of the parent so downstream hubs won't reject it. - - $s['route'] = $parent_item['route']; - $s['item_private'] = $parent_item['item_private']; - $s['obj_type'] = $objtype; - $s['obj'] = $object; - - if ($act->obj['conversation']) { - set_iconfig($s, 'ostatus', 'conversation', $act->obj['conversation'], 1); - } - - if ($act->recips && (!in_array(ACTIVITY_PUBLIC_INBOX, $act->recips))) - $s['item_private'] = 1; - - set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); - - $result = item_store($s); - - if ($result['success']) { - // if the message isn't already being relayed, notify others - if (intval($parent_item['item_origin'])) - Master::Summon(['Notifier', 'comment-import', $result['item_id']]); - sync_an_item($channel['channel_id'], $result['item_id']); - } - - return; - } public static function bb_attach($item) { diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 265bcb376..4a327e24f 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1672,24 +1672,13 @@ class Libzot { } if ($arr['verb'] === 'Announce') { - - // TODO: move this to background - - if (!Activity::fetch_and_store_parents($channel, $sender, $arr, true)) { - continue; - } - - $parent = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($arr['parent_mid']), - intval($channel['channel_id']) - ); - + Master::Summon(['Fetchparents', $channel['channel_id'], $sender, $arr['mid'], true]); } else { Master::Summon(['Zotconvo', $channel['channel_id'], $arr['parent_mid']]); - continue; } + continue; } logger('checking source: "' . $arr['mid'] . '" != "' . $arr['parent_mid'] . '"'); -- cgit v1.2.3 From 5e780ba089aa8493eb5bec30558345b070ef808c Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 27 Jan 2024 16:36:26 +0000 Subject: implement short time object cache to reduce network calls and some cleanup --- Zotlabs/Lib/ASCache.php | 33 ++++ Zotlabs/Lib/Activity.php | 335 +++++++--------------------------------- Zotlabs/Lib/ActivityStreams.php | 21 ++- Zotlabs/Lib/Cache.php | 16 +- 4 files changed, 118 insertions(+), 287 deletions(-) create mode 100644 Zotlabs/Lib/ASCache.php (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/ASCache.php b/Zotlabs/Lib/ASCache.php new file mode 100644 index 000000000..63bd73ea7 --- /dev/null +++ b/Zotlabs/Lib/ASCache.php @@ -0,0 +1,33 @@ + $v) - set_abconfig($channel['channel_id'], $ret['xchan_hash'], 'my_perms', $k, $v); + AbConfig::Set($channel['channel_id'], $ret['xchan_hash'], 'my_perms', $k, $v); if ($their_perms) foreach ($their_perms as $k => $v) - set_abconfig($channel['channel_id'], $ret['xchan_hash'], 'their_perms', $k, $v); + AbConfig::Set($channel['channel_id'], $ret['xchan_hash'], 'their_perms', $k, $v); if ($r) { logger("New ActivityPub follower for {$channel['channel_name']}"); @@ -1540,7 +1541,7 @@ class Activity { unset($clone['abook_account']); unset($clone['abook_channel']); - $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']); + $abconfig = AbConfig::Load($channel['channel_id'], $clone['abook_xchan']); if ($abconfig) $clone['abconfig'] = $abconfig; @@ -1581,7 +1582,7 @@ class Activity { ); if ($r) { // remove all permissions they provided - del_abconfig($channel['channel_id'], $r[0]['xchan_hash'], 'system', 'their_perms'); + AbConfig::Delete($channel['channel_id'], $r[0]['xchan_hash'], 'system', 'their_perms'); } } @@ -1881,251 +1882,6 @@ class Activity { return (($a_width > $b_width) ? -1 : 1); } - static function create_note($channel, $observer_hash, $act) { - - $s = []; - $is_sys_channel = is_sys_channel($channel['channel_id']); - $parent = ((array_key_exists('inReplyTo', $act->obj)) ? urldecode($act->obj['inReplyTo']) : ''); - - if ($parent) { - - $r = q("select * from item where uid = %d and ( mid = '%s' or mid = '%s' ) limit 1", - intval($channel['channel_id']), - dbesc($parent), - dbesc(basename($parent)) - ); - - if (!$r) { - logger('parent not found.'); - return; - } - - if ($r[0]['owner_xchan'] === $channel['channel_hash']) { - if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') && !$is_sys_channel) { - logger('no comment permission.'); - return; - } - } - - $s['parent_mid'] = $r[0]['mid']; - $s['owner_xchan'] = $r[0]['owner_xchan']; - $s['author_xchan'] = $observer_hash; - - } - else { - if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') && !$is_sys_channel) { - logger('no send_stream permission'); - return; - } - $s['owner_xchan'] = $s['author_xchan'] = $observer_hash; - } - - if ($act->recips && (!in_array(ACTIVITY_PUBLIC_INBOX, $act->recips))) - $s['item_private'] = 1; - - - if (array_key_exists('directMessage', $act->obj) && intval($act->obj['directMessage'])) { - $s['item_private'] = 2; - } - - if (intval($s['item_private']) === 2) { - if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'post_mail')) { - logger('no post_mail permission'); - return; - } - } - - $content = self::get_content($act->obj); - - if (!$content) { - logger('no content'); - return; - } - - $s['aid'] = $channel['channel_account_id']; - $s['uid'] = $channel['channel_id']; - - // Make sure we use the zot6 identity where applicable - - $s['author_xchan'] = self::find_best_identity($s['author_xchan']); - $s['owner_xchan'] = self::find_best_identity($s['owner_xchan']); - - if (!$s['author_xchan']) { - logger('No author: ' . print_r($act, true)); - } - - if (!$s['owner_xchan']) { - logger('No owner: ' . print_r($act, true)); - } - - if (!$s['author_xchan'] || !$s['owner_xchan']) - return; - - $s['mid'] = urldecode($act->obj['id']); - $s['uuid'] = $act->obj['diaspora:guid']; - $s['plink'] = urldecode($act->obj['id']); - - - if ($act->data['published']) { - $s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']); - } - elseif ($act->obj['published']) { - $s['created'] = datetime_convert('UTC', 'UTC', $act->obj['published']); - } - if ($act->data['updated']) { - $s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']); - } - elseif ($act->obj['updated']) { - $s['edited'] = datetime_convert('UTC', 'UTC', $act->obj['updated']); - } - if ($act->data['expires']) { - $s['expires'] = datetime_convert('UTC', 'UTC', $act->data['expires']); - } - elseif ($act->obj['expires']) { - $s['expires'] = datetime_convert('UTC', 'UTC', $act->obj['expires']); - } - - if (!$s['created']) - $s['created'] = datetime_convert(); - - if (!$s['edited']) - $s['edited'] = $s['created']; - - - if (!$s['parent_mid']) - $s['parent_mid'] = $s['mid']; - - - $s['title'] = self::bb_content($content, 'name'); - $s['summary'] = self::bb_content($content, 'summary'); - $s['body'] = self::bb_content($content, 'content'); - $s['verb'] = ACTIVITY_POST; - $s['obj_type'] = ACTIVITY_OBJ_NOTE; - - $generator = $act->get_property_obj('generator'); - if (!$generator) - $generator = $act->get_property_obj('generator', $act->obj); - - if ($generator && array_key_exists('type', $generator) - && in_array($generator['type'], ['Application', 'Service']) && array_key_exists('name', $generator)) { - $s['app'] = escape_tags($generator['name']); - } - - if ($channel['channel_system']) { - $incl = get_config('system','pubstream_incl'); - $excl = get_config('system','pubstream_excl'); - - if(($incl || $excl) && !MessageFilter::evaluate($s, $incl, $excl)) { - logger('post is filtered'); - return; - } - } - - $abook = q("select * from abook where (abook_xchan = '%s' OR abook_xchan = '%s') and abook_channel = %d ", - dbesc($s['author_xchan']), - dbesc($s['owner_xchan']), - intval($channel['channel_id']) - ); - - if ($abook) { - if (!post_is_importable($channel['channel_id'], $s, $abook)) { - logger('post is filtered'); - return; - } - } - - if ($act->obj['conversation']) { - set_iconfig($s, 'ostatus', 'conversation', $act->obj['conversation'], 1); - } - - $a = self::decode_taxonomy($act->obj); - if ($a) { - $s['term'] = $a; - } - - $a = self::decode_attachment($act->obj); - if ($a) { - $s['attach'] = $a; - } - - if ($act->obj['type'] === 'Note' && $s['attach']) { - $s['body'] .= self::bb_attach($s['attach'], $s['body']); - } - - // we will need a hook here to extract magnet links e.g. peertube - // right now just link to the largest mp4 we find that will fit in our - // standard content region - - if ($act->obj['type'] === 'Video') { - - $vtypes = [ - 'video/mp4', - 'video/ogg', - 'video/webm' - ]; - - $mps = []; - if (array_key_exists('url', $act->obj) && is_array($act->obj['url'])) { - foreach ($act->obj['url'] as $vurl) { - if (in_array($vurl['mimeType'], $vtypes)) { - if (!array_key_exists('width', $vurl)) { - $vurl['width'] = 0; - } - $mps[] = $vurl; - } - } - } - if ($mps) { - usort($mps, [__CLASS__, 'vid_sort']); - foreach ($mps as $m) { - if (intval($m['width']) < 500) { - $s['body'] .= "\n\n" . '[video]' . $m['href'] . '[/video]'; - break; - } - } - } - } - - set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); - if ($parent) { - set_iconfig($s, 'activitypub', 'rawmsg', $act->raw, 1); - } - - $x = null; - - $r = q("select created, edited from item where mid = '%s' and uid = %d limit 1", - dbesc($s['mid']), - intval($s['uid']) - ); - if ($r) { - if ($s['edited'] > $r[0]['edited']) { - $x = item_store_update($s); - } - else { - return; - } - } - else { - $x = item_store($s); - } - - if (is_array($x) && $x['item_id']) { - if ($parent) { - if ($s['owner_xchan'] === $channel['channel_hash']) { - // We are the owner of this conversation, so send all received comments back downstream - Master::Summon(['Notifier', 'comment-import', $x['item_id']]); - } - $r = q("select * from item where id = %d limit 1", - intval($x['item_id']) - ); - if ($r) { - send_status_notifications($x['item_id'], $r[0]); - } - } - sync_an_item($channel['channel_id'], $x['item_id']); - } - - } static function get_actor_bbmention($id) { @@ -2305,7 +2061,16 @@ class Activity { $content = self::get_content($act->obj); } - $s['mid'] = $act->objprop('id') ?: $act->obj; + $s['mid'] = $act->objprop('id'); + + if (!$s['mid'] && is_string($act->obj)) { + $s['mid'] = $act->obj; + } + + // pleroma fetched activities + if (!$s['mid'] && isset($act->obj['data']['id'])) { + $s['mid'] = $act->obj['data']['id']; + } if (!$s['mid']) { return false; @@ -2883,22 +2648,22 @@ class Activity { } if ($ap_rawmsg) { - set_iconfig($s, 'activitypub', 'rawmsg', $ap_rawmsg, 1); + IConfig::Set($s, 'activitypub', 'rawmsg', $ap_rawmsg, 1); } elseif (!array_key_exists('signed', $raw_arr)) { - set_iconfig($s, 'activitypub', 'rawmsg', $act->raw, 1); + IConfig::Set($s, 'activitypub', 'rawmsg', $act->raw, 1); } if ($diaspora_rawmsg) { - set_iconfig($s, 'diaspora', 'fields', $diaspora_rawmsg, 1); + IConfig::Set($s, 'diaspora', 'fields', $diaspora_rawmsg, 1); } if ($act->raw_recips) { - set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); + IConfig::Set($s, 'activitypub', 'recips', $act->raw_recips); } if ($act->objprop('type') === 'Event' && $act->objprop('timezone')) { - set_iconfig($s, 'event', 'timezone', $act->objprop('timezone'), true); + IConfig::Set($s, 'event', 'timezone', $act->objprop('timezone'), true); } $hookinfo = [ @@ -2947,14 +2712,18 @@ class Activity { } if ($fetch_parents) { - Master::Summon(['Fetchparents', $channel['channel_id'], $observer_hash, $item['mid'], $force]); + // Cache::set($item['mid'], 'json:' . $act->raw); + App::$cache['fetch_objects'][$item['mid']]['channels'][] = $channel['channel_id']; + App::$cache['fetch_objects'][$item['mid']]['force'] = intval($force); + + //Master::Summon(['Fetchparents', $channel['channel_id'], $observer_hash, $item['mid'], $force]); //self::fetch_and_store_parents($channel, $observer_hash, $item, $act, $force); return; } - - logger('no parent'); - return; } + + logger('no parent'); + return; } @@ -2998,7 +2767,7 @@ class Activity { }*/ if (!$allowed) { - if (get_pconfig($channel['channel_id'], 'system', 'moderate_unsolicited_comments') && $item['obj_type'] !== 'Answer') { + if (PConfig::Get($channel['channel_id'], 'system', 'moderate_unsolicited_comments') && $item['obj_type'] !== 'Answer') { $item['item_blocked'] = ITEM_MODERATED; $allowed = true; } @@ -3043,7 +2812,7 @@ class Activity { if (tgroup_check($channel['channel_id'], $item) && (!$is_child_node)) { // for forum deliveries, make sure we keep a copy of the signed original - set_iconfig($item, 'activitypub', 'rawmsg', $act->raw, 1); + IConfig::Set($item, 'activitypub', 'rawmsg', $act->raw, 1); $allowed = true; } @@ -3103,6 +2872,7 @@ class Activity { $item['author_xchan'] = self::find_best_identity($item['author_xchan']); $item['owner_xchan'] = self::find_best_identity($item['owner_xchan']); + $item['source_xchan'] = ((!empty($item['source_xchan'])) ? self::find_best_identity($item['source_xchan']) : ''); if (!$item['author_xchan']) { logger('No author: ' . print_r($act, true)); @@ -3116,8 +2886,8 @@ class Activity { return; if ($channel['channel_system']) { - $incl = get_config('system','pubstream_incl'); - $excl = get_config('system','pubstream_excl'); + $incl = Config::Get('system','pubstream_incl'); + $excl = Config::Get('system','pubstream_excl'); if(($incl || $excl) && !MessageFilter::evaluate($item, $incl, $excl)) { logger('post is filtered'); @@ -3125,9 +2895,10 @@ class Activity { } } - $abook = q("select * from abook where ( abook_xchan = '%s' OR abook_xchan = '%s') and abook_channel = %d ", + $abook = q("select * from abook where ( abook_xchan = '%s' OR abook_xchan = '%s' OR abook_xchan = '%s') and abook_channel = %d ", dbesc($item['author_xchan']), dbesc($item['owner_xchan']), + dbesc($item['source_xchan']), intval($channel['channel_id']) ); @@ -3139,13 +2910,13 @@ class Activity { } if (array_key_exists('conversation', $act->obj)) { - set_iconfig($item, 'ostatus', 'conversation', $act->obj['conversation'], 1); + IConfig::Set($item, 'ostatus', 'conversation', $act->obj['conversation'], 1); } // This isn't perfect but the best we can do for now. $item['comment_policy'] = ((isset($act->data['commentPolicy'])) ? $act->data['commentPolicy'] : 'authenticated'); - set_iconfig($item, 'activitypub', 'recips', $act->raw_recips); + IConfig::Set($item, 'activitypub', 'recips', $act->raw_recips); if (intval($act->sigok)) { $item['item_verified'] = 1; @@ -3311,10 +3082,16 @@ class Activity { $i = 0; while ($current_item['parent_mid'] !== $current_item['mid']) { - $n = self::fetch($current_item['parent_mid'], $channel); - - if (!$n) { - break; + $cached = ASCache::Get($current_item['parent_mid']); + if ($cached) { + $n = unserialise($cached); + } + else { + $n = self::fetch($current_item['parent_mid'], $channel); + if (!$n) { + break; + } + ASCache::Set($current_item['parent_mid'], serialise($n)); } $a = new ActivityStreams($n); diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index 0770f2040..3749126d3 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -90,6 +90,15 @@ class ActivityStreams { // Attempt to assemble an Activity from what we were given. if ($this->is_valid()) { $this->id = $this->get_property_obj('id'); + + if (!$this->id) { + logger('Data with mmissing id: ' . print_r($this->data, true)); + return; + } + + // cache for future use + ASCache::Set($this->id, 'json:' . $this->raw); + $this->type = $this->get_primary_type(); $this->actor = $this->get_actor('actor', '', ''); $this->obj = $this->get_compound_property('object'); @@ -394,12 +403,22 @@ class ActivityStreams { $x = $this->get_property_obj($property, $base, $namespace); if ($this->is_url($x)) { - $y = $this->fetch_property($x); + $cached = ASCache::Get($x); + if ($cached) { + $y = unserialise($cached); + } + else { + $y = $this->fetch_property($x); + if ($y) { + ASCache::Set($x, serialise($y)); + } + } if (is_array($y)) { $x = $y; } } + // verify and unpack JSalmon signature if present if (is_array($x) && array_key_exists('signed', $x)) { diff --git a/Zotlabs/Lib/Cache.php b/Zotlabs/Lib/Cache.php index 60bf64611..f3f520496 100644 --- a/Zotlabs/Lib/Cache.php +++ b/Zotlabs/Lib/Cache.php @@ -17,8 +17,8 @@ class Cache { */ public static function get($key, $age = '') { - - $hash = hash('whirlpool',$key); +// $hash = hash('whirlpool',$key); + $hash = uuid_from_url($key); $r = q("SELECT v FROM cache WHERE k = '%s' AND updated > %s - INTERVAL %s LIMIT 1", dbesc($hash), @@ -32,23 +32,25 @@ class Cache { } public static function set($key,$value) { +// $hash = hash('whirlpool',$key); + $hash = uuid_from_url($key); - $hash = hash('whirlpool',$key); - - $r = q("SELECT * FROM cache WHERE k = '%s' limit 1", + $r = q("SELECT * FROM cache WHERE k = '%s' LIMIT 1", dbesc($hash) ); if($r) { q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'", dbesc($value), dbesc(datetime_convert()), - dbesc($hash)); + dbesc($hash) + ); } else { q("INSERT INTO cache (k, v, updated) VALUES ('%s', '%s', '%s')", dbesc($hash), dbesc($value), - dbesc(datetime_convert())); + dbesc(datetime_convert()) + ); } } } -- cgit v1.2.3 From 09465619e53c9c0a04ee73cecc3fc2d87ee74d55 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 28 Jan 2024 17:03:05 +0000 Subject: enable object cash by default, introduce system.cache_expire_days and default to 7, default system.default_expire_days to 30 and system.active_expire_days to 7 --- Zotlabs/Lib/ASCache.php | 2 +- Zotlabs/Lib/Activity.php | 2 ++ Zotlabs/Lib/ActivityStreams.php | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/ASCache.php b/Zotlabs/Lib/ASCache.php index 63bd73ea7..4904a1d8a 100644 --- a/Zotlabs/Lib/ASCache.php +++ b/Zotlabs/Lib/ASCache.php @@ -8,7 +8,7 @@ namespace Zotlabs\Lib; class ASCache { public static function isEnabled() { - return Config::Get('system', 'as_object_cache_enabled', false); + return Config::Get('system', 'as_object_cache_enabled', true); } public static function getAge() { diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index a225e551b..a6a194045 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3084,9 +3084,11 @@ class Activity { while ($current_item['parent_mid'] !== $current_item['mid']) { $cached = ASCache::Get($current_item['parent_mid']); if ($cached) { + // logger('cached: ' . $current_item['parent_mid']); $n = unserialise($cached); } else { + // logger('fetching: ' . $current_item['parent_mid']); $n = self::fetch($current_item['parent_mid'], $channel); if (!$n) { break; diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index 3749126d3..b37efdd26 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -405,9 +405,11 @@ class ActivityStreams { if ($this->is_url($x)) { $cached = ASCache::Get($x); if ($cached) { + // logger('AS cached: ' . $x); $y = unserialise($cached); } else { + // logger('AS fetching: ' . $x); $y = $this->fetch_property($x); if ($y) { ASCache::Set($x, serialise($y)); -- cgit v1.2.3 From 29489f62cfc27705a0993532929c244d9d99b7bf Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 29 Jan 2024 10:33:13 +0000 Subject: introduce Activity::init_background_fetch() and refactor zotconvo to implement it --- Zotlabs/Lib/Activity.php | 57 +++++++++++++++++++++++++++++++++++++++++++----- Zotlabs/Lib/Libzot.php | 12 +++++++--- 2 files changed, 60 insertions(+), 9 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index a6a194045..a795d8590 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2712,12 +2712,8 @@ class Activity { } if ($fetch_parents) { - // Cache::set($item['mid'], 'json:' . $act->raw); - App::$cache['fetch_objects'][$item['mid']]['channels'][] = $channel['channel_id']; - App::$cache['fetch_objects'][$item['mid']]['force'] = intval($force); - - //Master::Summon(['Fetchparents', $channel['channel_id'], $observer_hash, $item['mid'], $force]); - //self::fetch_and_store_parents($channel, $observer_hash, $item, $act, $force); + App::$cache['as_fetch_objects'][$item['mid']]['channels'][] = $channel['channel_id']; + App::$cache['as_fetch_objects'][$item['mid']]['force'] = intval($force); return; } } @@ -3699,5 +3695,54 @@ class Activity { return $arr; } + /** + * @brief Prepares the arguments and inititates the Fetchparents or Zotconvo daemon. + * @param string $observer + * + */ + + public static function init_background_fetch(string $observer_hash = '') { + hz_syslog(print_r(App::$cache, true)); + + if (isset(App::$cache['zot_fetch_objects'])) { + $channels_str = ''; + + foreach (App::$cache['zot_fetch_objects'] as $mid => $info) { + $force = $info['force']; + + foreach ($info['channels'] as $c) { + if ($channels_str) { + $channels_str .= ','; + } + $channels_str .= $c; + } + + Master::Summon(['Zotconvo', $channels_str, $mid, $force]); + } + } + + if (isset(App::$cache['as_fetch_objects'])) { + if (!$observer_hash) { + logger('Attempt to initiate Fetchparents daemon without observer'); + return; + } + + $channels_str = ''; + + foreach (App::$cache['as_fetch_objects'] as $mid => $info) { + $force = $info['force']; + + foreach ($info['channels'] as $c) { + if ($channels_str) { + $channels_str .= ','; + } + $channels_str .= $c; + } + + Master::Summon(['Fetchparents', $channels_str, $observer_hash, $mid, $force]); + } + } + } + } diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 4a327e24f..70ca2d84b 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -2,6 +2,7 @@ namespace Zotlabs\Lib; +use App; use Zotlabs\Web\HTTPSig; use Zotlabs\Access\Permissions; use Zotlabs\Access\PermissionLimits; @@ -1321,6 +1322,9 @@ class Libzot { if ($result) { $return = array_merge($return, $result); } + + Activity::init_background_fetch(); + return $return; } @@ -1672,10 +1676,12 @@ class Libzot { } if ($arr['verb'] === 'Announce') { - Master::Summon(['Fetchparents', $channel['channel_id'], $sender, $arr['mid'], true]); + App::$cache['as_fetch_objects'][$arr['mid']]['channels'][] = $channel['channel_id']; + App::$cache['as_fetch_objects'][$arr['mid']]['force'] = true; } else { - Master::Summon(['Zotconvo', $channel['channel_id'], $arr['parent_mid']]); + App::$cache['zot_fetch_objects'][$arr['mid']]['channels'][] = $channel['channel_id']; + App::$cache['zot_fetch_objects'][$arr['mid']]['force'] = false; } continue; @@ -2977,7 +2983,7 @@ class Libzot { $ret['site']['admin'] = get_config('system', 'admin_email'); $visible_plugins = []; - if (is_array(\App::$plugins) && count(\App::$plugins)) { + if (is_array(App::$plugins) && count(App::$plugins)) { $r = q("select * from addon where hidden = 0"); if ($r) foreach ($r as $rr) -- cgit v1.2.3 From 26ee56f39cbafcc6f7043026708cafdd1523bcec Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 29 Jan 2024 10:39:15 +0000 Subject: remove logging --- Zotlabs/Lib/Activity.php | 2 -- 1 file changed, 2 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index a795d8590..a25344611 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3702,8 +3702,6 @@ class Activity { */ public static function init_background_fetch(string $observer_hash = '') { - hz_syslog(print_r(App::$cache, true)); - if (isset(App::$cache['zot_fetch_objects'])) { $channels_str = ''; -- cgit v1.2.3 From dd204ec34f473d7e0b133d35b08f3c4dc8d3ffef Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 1 Feb 2024 11:42:55 +0000 Subject: start using uuid for internal reference instead of base64 encoded mid --- Zotlabs/Lib/Enotify.php | 16 +++++++++------- Zotlabs/Lib/ThreadItem.php | 19 ++++++++++--------- Zotlabs/Lib/ThreadStream.php | 4 ++-- 3 files changed, 21 insertions(+), 18 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index d8e6f575a..a9eaf3136 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -486,6 +486,8 @@ class Enotify { require_once('include/html2bbcode.php'); +/* + do { $dups = false; $hash = random_string(); @@ -494,10 +496,12 @@ class Enotify { if ($r) $dups = true; } while ($dups === true); +*/ + $datarray = []; - $datarray['hash'] = $hash; + $datarray['hash'] = $params['item']['uuid'] ?? new_uuid(); $datarray['sender_hash'] = $sender['xchan_hash']; $datarray['xname'] = $sender['xchan_name']; $datarray['url'] = $sender['xchan_url']; @@ -557,7 +561,7 @@ class Enotify { ); $r = q("select id from notify where hash = '%s' and uid = %d limit 1", - dbesc($hash), + dbesc($datarray['hash']), intval($recip['channel_id']) ); if ($r) { @@ -871,7 +875,8 @@ class Enotify { 'photo' => $item['author']['xchan_photo_s'], 'when' => (($edit) ? datetime_convert('UTC', date_default_timezone_get(), $item['edited']) : datetime_convert('UTC', date_default_timezone_get(), $item['created'])), 'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'), - 'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''), + // 'b64mid' => (($item['mid']) ? gen_link_id($item['mid']) : ''), + 'b64mid' => (($item['uuid']) ? $item['uuid'] : ''), //'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? gen_link_id($item['thr_parent']) : gen_link_id($item['mid'])), 'thread_top' => (($item['item_thread_top']) ? true : false), 'message' => bbcode(escape_tags($itemem_text)), @@ -897,9 +902,6 @@ class Enotify { if(strpos($message, $tt['xname']) === 0) $message = substr($message, strlen($tt['xname']) + 1); - $mid = basename($tt['link']); - - $b64mid = gen_link_id($mid); $x = [ 'notify_link' => (($tt['ntype'] === NOTIFY_MAIL) ? $tt['link'] : z_root() . '/notify/view/' . $tt['id']), 'name' => $tt['xname'], @@ -907,7 +909,7 @@ class Enotify { 'photo' => $tt['photo'], 'when' => datetime_convert('UTC', date_default_timezone_get(), $tt['created']), 'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'), - 'b64mid' => (($tt['otype'] == 'item') ? $b64mid : ''), + 'b64mid' => (($tt['otype'] == 'item') ? $tt['hash'] : ''), 'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : ''), 'message' => $message ]; diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 77f26c386..b6df1baf1 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -34,6 +34,7 @@ class ThreadItem { private $channel = null; private $display_mode = 'normal'; private $reload = ''; + private $mid_uuid_map = []; public function __construct($data) { @@ -46,6 +47,7 @@ class ThreadItem { // Prepare the children if(isset($data['children'])) { + foreach($data['children'] as $item) { /* @@ -56,7 +58,6 @@ class ThreadItem { continue; } - $child = new ThreadItem($item); $this->add_child($child); } @@ -65,6 +66,8 @@ class ThreadItem { unset($this->data['children']); } + + // allow a site to configure the order and content of the reaction emoji list if($this->toplevel) { $x = get_config('system','reactions'); @@ -82,7 +85,7 @@ class ThreadItem { * _ false on failure */ - public function get_template_data($conv_responses, $thread_level=1, $conv_flags = []) { + public function get_template_data($conv_responses, $mid_uuid_map, $thread_level=1, $conv_flags = []) { $result = []; $item = $this->get_data(); @@ -351,7 +354,7 @@ class ThreadItem { $dreport_link = ''; if((intval($item['item_type']) == ITEM_TYPE_POST) && (! get_config('system','disable_dreport')) && strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC',"now - $keep_reports days")) > 0) { $dreport = t('Delivery Report'); - $dreport_link = gen_link_id($item['mid']); + $dreport_link = '?mid=' . $item['mid']; } $is_new = false; @@ -381,8 +384,8 @@ class ThreadItem { call_hooks('dropdown_extras',$dropdown_extras_arr); $dropdown_extras = $dropdown_extras_arr['dropdown_extras']; - $midb64 = gen_link_id($item['mid']); - $mids = [ $midb64 ]; + //$midb64 = gen_link_id($item['mid']); + $mids = [ $item['uuid'] ]; $response_mids = []; foreach($response_verbs as $v) { if(isset($conv_responses[$v]['mids'][$item['mid']])) { @@ -530,14 +533,12 @@ class ThreadItem { 'wait' => t('Please wait'), 'thread_level' => $thread_level, 'settings' => $settings, - 'thr_parent' => (($item['parent_mid'] != $item['thr_parent']) ? gen_link_id($item['thr_parent']) : ''), + 'thr_parent_uuid' => (($item['parent_mid'] != $item['thr_parent']) ? $mid_uuid_map[$item['thr_parent']] : ''), 'contact_id' => (($contact) ? $contact['abook_id'] : ''), 'moderate' => ($item['item_blocked'] == ITEM_MODERATED), 'moderate_approve' => t('Approve'), 'moderate_delete' => t('Delete'), 'rtl' => in_array($item['lang'], rtl_languages()), - - ); $arr = array('item' => $item, 'output' => $tmp_item); @@ -560,7 +561,7 @@ class ThreadItem { if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) { foreach($children as $child) { - $result['children'][] = $child->get_template_data($conv_responses, $thread_level + 1,$conv_flags); + $result['children'][] = $child->get_template_data($conv_responses, $mid_uuid_map, $thread_level + 1,$conv_flags); } // Collapse if(($nb_children > $visible_comments) || ($thread_level > 1)) { diff --git a/Zotlabs/Lib/ThreadStream.php b/Zotlabs/Lib/ThreadStream.php index 2ad24a690..72d2bd2f8 100644 --- a/Zotlabs/Lib/ThreadStream.php +++ b/Zotlabs/Lib/ThreadStream.php @@ -211,7 +211,7 @@ class ThreadStream { * _ The data requested on success * _ false on failure */ - public function get_template_data($conv_responses) { + public function get_template_data($conv_responses, $mid_uuid_map) { $result = array(); foreach($this->threads as $item) { @@ -220,7 +220,7 @@ class ThreadStream { $item_data = $this->prepared_item; } else { - $item_data = $item->get_template_data($conv_responses); + $item_data = $item->get_template_data($conv_responses, $mid_uuid_map); } if(!$item_data) { logger('Failed to get item template data ('. $item->get_id() .').', LOGGER_DEBUG, LOG_ERR); -- cgit v1.2.3 From decc8f21621f6c0bb129285757e6d24f278216d2 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 1 Feb 2024 14:14:53 +0000 Subject: strip a possible fragment --- Zotlabs/Lib/Activity.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index a25344611..782773da3 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3500,6 +3500,8 @@ class Activity { static function get_actor_hublocs($url, $options = 'all') { + $url = ((strpos($url, '#')) ? substr($url, 0, strpos($url, '#')) : $url); + switch ($options) { case 'activitypub': $hublocs = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_hash = '%s' and hubloc_deleted = 0 order by hubloc_id desc", -- cgit v1.2.3 From 2e155892fe88c877c226fc5a10402a05c05fe8cd Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 1 Feb 2024 16:00:17 +0000 Subject: testing JcsEddsa2022 sigs --- Zotlabs/Lib/ActivityStreams.php | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index b37efdd26..b3b58af89 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -524,16 +524,22 @@ class ActivityStreams { $signer = $this->get_property_obj('verificationMethod', $this->sig); $parseUrl = parse_url($signer); - if (!empty($parseUrl['fragment']) && str_starts_with($parseUrl['fragment'],'z6Mk')) { - $publicKey = $parseUrl['fragment']; + + if (isset($parseUrl['fragment'])) { + if (str_starts_with($parseUrl['fragment'], 'z6Mk')) { + $publicKey = $parseUrl['fragment']; + } unset($parseUrl['fragment']); + } + + if (isset($parseUrl['query'])) { unset($parseUrl['query']); } $url = unparse_url($parseUrl); - //$this->signer = [ 'id' => $url ]; $hublocs = Activity::get_actor_hublocs($url); + $hasStoredKey = false; if ($hublocs) { foreach ($hublocs as $hubloc) { @@ -543,14 +549,26 @@ class ActivityStreams { } } } + if (!$hasStoredKey) { $this->signer = Activity::get_actor($url); - if ($this->signer - && !empty($this->signer['assertionMethod']) - && !empty($this->signer['assertionMethod']['publicKeyMultibase'])) { - $publicKey = $this->signer['assertionMethod']['publicKeyMultibase']; + + if (isset($this->signer['assertionMethod'])) { + if (!isset($this->signer['assertionMethod'][0])) { + $this->signer['assertionMethod'] = [$this->signer['assertionMethod']]; + } + + foreach($this->signer['assertionMethod'] as $am) { + if ($url === $am['controller'] && + $am['type'] === 'Multikey' && + str_starts_with($am['publicKeyMultibase'], 'z6Mk') + ) { + $publicKey = $am['publicKeyMultibase']; + } + } } } + if ($publicKey) { $this->sigok = (new JcsEddsa2022)->verify($this->data, $publicKey); } -- cgit v1.2.3 From 8515aa6966536c40f1a6c3e4cf0647401485f7d8 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 1 Feb 2024 16:29:23 +0000 Subject: fix issues related to b64mid to uuid conversion --- Zotlabs/Lib/ThreadItem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index b6df1baf1..016dc5d25 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -384,7 +384,7 @@ class ThreadItem { call_hooks('dropdown_extras',$dropdown_extras_arr); $dropdown_extras = $dropdown_extras_arr['dropdown_extras']; - //$midb64 = gen_link_id($item['mid']); + $midb64 = $item['uuid']; $mids = [ $item['uuid'] ]; $response_mids = []; foreach($response_verbs as $v) { -- cgit v1.2.3 From c41831aff900d40c89e57dc7c1260a7d3d98323f Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 1 Feb 2024 17:05:00 +0000 Subject: fix conv_list template --- Zotlabs/Lib/ThreadItem.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 016dc5d25..07cc88581 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -373,8 +373,8 @@ class ThreadItem { if($conv->get_mode() === 'channel') $viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid'])); - $comment_count_txt = sprintf(tt('%d Comment', '%d Comments', $total_children), $total_children); - $list_unseen_txt = (($unseen_comments) ? sprintf(t('%d unseen'), $unseen_comments) : ''); + $comment_count_txt = ['label' => sprintf(tt('%d Comment', '%d Comments', $total_children), $total_children), 'count' => $total_children]; + $list_unseen_txt = $unseen_comments ? ['label' => sprintf(t('%d unseen'), $unseen_comments), 'count' => $unseen_comments] : []; $children = $this->get_children(); @@ -501,7 +501,7 @@ class ThreadItem { 'comment_count' => $total_children, 'comment_count_txt' => $comment_count_txt, 'list_unseen_txt' => $list_unseen_txt, - 'markseen' => t('Mark all seen'), + 'markseen' => t('Mark all comments seen'), 'responses' => $responses, 'my_responses' => $my_responses, /* -- cgit v1.2.3 From 8ad7376865b45f8943499c803a6014d961a73cb4 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 1 Feb 2024 17:12:43 +0000 Subject: more fix conv_list template --- Zotlabs/Lib/ThreadItem.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 07cc88581..6b07e32e9 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -373,7 +373,7 @@ class ThreadItem { if($conv->get_mode() === 'channel') $viewthread = z_root() . '/channel/' . $owner_address . '?f=&mid=' . urlencode(gen_link_id($item['mid'])); - $comment_count_txt = ['label' => sprintf(tt('%d Comment', '%d Comments', $total_children), $total_children), 'count' => $total_children]; + $comment_count_txt = ['label' => sprintf(tt('%d comment', '%d comments', $total_children), $total_children), 'count' => $total_children]; $list_unseen_txt = $unseen_comments ? ['label' => sprintf(t('%d unseen'), $unseen_comments), 'count' => $unseen_comments] : []; $children = $this->get_children(); @@ -566,7 +566,7 @@ class ThreadItem { // Collapse if(($nb_children > $visible_comments) || ($thread_level > 1)) { $result['children'][0]['comment_firstcollapsed'] = true; - $result['children'][0]['num_comments'] = $comment_count_txt; + $result['children'][0]['num_comments'] = $comment_count_txt['label']; $result['children'][0]['hide_text'] = sprintf( t('%s show all'), ''); if($thread_level > 1) { $result['children'][$nb_children - 1]['comment_lastcollapsed'] = true; -- cgit v1.2.3 From fab3c92a7c881be049cba62a950e90732d8c1ec5 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 2 Feb 2024 20:23:06 +0000 Subject: streams collection branch compatibility --- Zotlabs/Lib/Activity.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 782773da3..089fb3687 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1203,7 +1203,7 @@ class Activity { 'http://activitystrea.ms/schema/1.0/like' => 'Like', 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', 'http://purl.org/zot/activity/dislike' => 'Dislike', - 'http://activitystrea.ms/schema/1.0/tag' => 'Add', + // 'http://activitystrea.ms/schema/1.0/tag' => 'Add', 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow', 'http://activitystrea.ms/schema/1.0/stop-following' => 'Unfollow', @@ -1213,7 +1213,9 @@ class Activity { 'Announce' => 'Announce', 'Invite' => 'Invite', 'Delete' => 'Delete', - 'Undo' => 'Undo' + 'Undo' => 'Undo', + 'Add' => 'Add', + 'Remove' => 'Remove' ]; call_hooks('activity_mapper', $acts); @@ -1252,7 +1254,7 @@ class Activity { 'http://activitystrea.ms/schema/1.0/like' => 'Like', 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', 'http://purl.org/zot/activity/dislike' => 'Dislike', - 'http://activitystrea.ms/schema/1.0/tag' => 'Add', + // 'http://activitystrea.ms/schema/1.0/tag' => 'Add', 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow', 'http://activitystrea.ms/schema/1.0/stop-following' => 'Unfollow', @@ -1262,7 +1264,9 @@ class Activity { 'Announce' => 'Announce', 'Invite' => 'Invite', 'Delete' => 'Delete', - 'Undo' => 'Undo' + 'Undo' => 'Undo', + 'Add' => 'Add', + 'Remove' => 'Remove' ]; call_hooks('activity_decode_mapper', $acts); -- cgit v1.2.3 From 209651705db81d43a3a0546866467e0bf26fd7b9 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 4 Feb 2024 19:50:31 +0000 Subject: fix custom emoji reactions arriving from pleroma --- Zotlabs/Lib/Activity.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 089fb3687..ddd91f60b 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2187,9 +2187,22 @@ class Activity { if (in_array($act->type, ['EmojiReaction', 'EmojiReact'])) { // Pleroma reactions $t = trim(self::get_textfield($act->data, 'content')); + + // Unicode emojis if (mb_strlen($t) === 1) { $content['content'] = $t; } + // Custom emojis + elseif (preg_match('/^[:].*[:]$/i', $t, $match)) { + $content['content'] = $match[0]; + if (isset($act->data['tag']) && is_array($act->data['tag'])) { + foreach ($act->data['tag'] as $tag) { + if ($tag['type'] === 'Emoji' && $tag['name'] === trim($match[0], ':')) { + $content['content'] = '[img=32x32]' . $tag['id'] . '[/img]'; + } + } + } + } } } -- cgit v1.2.3 From 5f2e80849753928ee30e8420750b6218c64b4e25 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 7 Feb 2024 15:37:20 +0000 Subject: add uuid to dreport for internal use and and fix issues with conversation fetches --- Zotlabs/Lib/DReport.php | 52 ++++++++++++++++++++++++--------------------- Zotlabs/Lib/Libzot.php | 56 ++++++++++++++++++++++++++++--------------------- 2 files changed, 60 insertions(+), 48 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/DReport.php b/Zotlabs/Lib/DReport.php index f4f098d19..71e39a9d7 100644 --- a/Zotlabs/Lib/DReport.php +++ b/Zotlabs/Lib/DReport.php @@ -8,22 +8,24 @@ class DReport { private $recipient; private $name; private $message_id; + private $message_uuid; private $status; private $date; - function __construct($location,$sender,$recipient,$message_id,$status = 'deliver') { - $this->location = $location; - $this->sender = $sender; - $this->recipient = $recipient; - $this->name = EMPTY_STR; - $this->message_id = $message_id; - $this->status = $status; - $this->date = datetime_convert(); + function __construct($location, $sender, $recipient, $message_id, $message_uuid = '', $status = 'deliver') { + $this->location = $location; + $this->sender = $sender; + $this->recipient = $recipient; + $this->name = EMPTY_STR; + $this->message_id = $message_id; + $this->message_uuid = $message_uuid; + $this->status = $status; + $this->date = datetime_convert(); } function update($status) { - $this->status = $status; - $this->date = datetime_convert(); + $this->status = $status; + $this->date = datetime_convert(); } function set_name($name) { @@ -36,24 +38,26 @@ class DReport { function set($arr) { - $this->location = $arr['location']; - $this->sender = $arr['sender']; - $this->recipient = $arr['recipient']; - $this->name = $arr['name']; - $this->message_id = $arr['message_id']; - $this->status = $arr['status']; - $this->date = $arr['date']; + $this->location = $arr['location']; + $this->sender = $arr['sender']; + $this->recipient = $arr['recipient']; + $this->name = $arr['name']; + $this->message_id = $arr['message_id']; + $this->message_uuid = $arr['message_uuid'] ?? ''; + $this->status = $arr['status']; + $this->date = $arr['date']; } function get() { return array( - 'location' => $this->location, - 'sender' => $this->sender, - 'recipient' => $this->recipient, - 'name' => $this->name, - 'message_id' => $this->message_id, - 'status' => $this->status, - 'date' => $this->date + 'location' => $this->location, + 'sender' => $this->sender, + 'recipient' => $this->recipient, + 'name' => $this->name, + 'message_id' => $this->message_id, + 'message_uuid' => $this->message_uuid, + 'status' => $this->status, + 'date' => $this->date ); } diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 70ca2d84b..002ccedfc 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1302,6 +1302,8 @@ class Libzot { $relay = (($env['type'] === 'response') ? true : false); $result = self::process_delivery($env['sender'], $AS, $item, $deliveries, $relay, false, $message_request); + + Activity::init_background_fetch($env['sender']); } elseif ($env['type'] === 'sync') { // $item = get_channelsync_elements($data); @@ -1323,8 +1325,6 @@ class Libzot { $return = array_merge($return, $result); } - Activity::init_background_fetch(); - return $return; } @@ -1533,7 +1533,7 @@ class Libzot { $local_public = $public; $item_result = null; - $DR = new DReport(z_root(), $sender, $d, $arr['mid']); + $DR = new DReport(z_root(), $sender, $d, $arr['mid'], $arr['uuid']); $channel = channelx_by_hash($d); @@ -1671,7 +1671,7 @@ class Libzot { // the top level post is unlikely to be imported and // this is just an exercise in futility. - if ($relay || $request || $local_public || !perm_is_allowed($channel['channel_id'], $sender, 'send_stream')) { + if ($relay || $request || (!$local_public && !perm_is_allowed($channel['channel_id'], $sender, 'send_stream'))) { continue; } @@ -1755,7 +1755,7 @@ class Libzot { } if (!$tag_delivery && !$local_public) { - $allowed = (perm_is_allowed($channel['channel_id'], $sender, $perm)); + $allowed = perm_is_allowed($channel['channel_id'], $sender, $perm); $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system', 'permit_all_mentions') && i_am_mentioned($channel, $arr)); @@ -1789,18 +1789,17 @@ class Libzot { if ($request) { // Conversation fetches (e.g. $request == true) take place for - // a) new comments on expired posts - // b) if we received an announce - + // a) new comments on expired posts + // b) manual import of posts via search (in this case force will be true) + // c) import of conversations from friends of friends (those will currently only be accepted in the public stream) - // over-ride normal connection permissions for hyperdrive (friend-of-friend) conversations - // (if hyperdrive is enabled) and repeated posts by a friend. - // If $allowed is already true, this is probably the conversation of a direct friend or a - // conversation fetch for a new comment on an expired post + // If it is a toplevel post check permissions for the item author instead of the sender (we might want to remove this if we want friend of friend posts in the network stream). // Comments of all these activities are allowed and will only be rejected (later) if the parent // doesn't exist. if ($perm === 'send_stream') { + $allowed = perm_is_allowed($channel['channel_id'], $arr['author_xchan'], $perm); + if ($force) { $allowed = true; } @@ -2000,11 +1999,14 @@ class Libzot { $ret = []; - $signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' order by hubloc_id desc limit 1", dbesc($a['signature']['signer']) ); + $signer_hash = $signer[0]['hubloc_hash'] ?? $a['signature']['signer']; + $conv_owner = $signer_hash; + + $i = 0; foreach ($items as $activity) { @@ -2018,14 +2020,14 @@ class Libzot { } if (!$AS->is_valid()) { - logger('FOF Activity rejected: ' . print_r($activity, true)); + logger('Fetched activity rejected: ' . print_r($activity, true)); continue; } // logger($AS->debug()); if(empty($AS->actor['id'])) { - logger('No actor id: ' . print_r($AS, true)); + logger('Fetched activity no actor id: ' . print_r($AS, true)); continue; } @@ -2038,7 +2040,7 @@ class Libzot { $r = self::zot_record_preferred($r); } if (!$r) { - logger('FOF Activity: no actor'); + logger('Fetched activity: no actor'); continue; } } @@ -2053,7 +2055,7 @@ class Libzot { $ro = self::zot_record_preferred($ro); } if (!$ro) { - logger('FOF Activity: no obj actor'); + logger('Fetched activity: no obj actor'); continue; } } @@ -2068,13 +2070,17 @@ class Libzot { $arr['author_xchan'] = $r['hubloc_hash']; - if ($signer) { - $arr['owner_xchan'] = $signer[0]['hubloc_hash']; - } - else { - $arr['owner_xchan'] = $a['signature']['signer']; + if ($i === 0) { + // Set the author of the toplevel post as conv_owner + $conv_owner = $r['hubloc_hash']; } + $arr['owner_xchan'] = $conv_owner; + $arr['source_xchan'] = $signer_hash; + + // WARNING: the presence of both source_xchan and non-zero item_uplink here will cause a delivery loop + $arr['item_uplink'] = 0; + if (isset($AS->meta['hubloc']) || $arr['author_xchan'] === $arr['owner_xchan']) { $arr['item_verified'] = true; } @@ -2087,13 +2093,15 @@ class Libzot { } } - logger('FOF Activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); - logger('FOF Activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG); + logger('Fetched activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); + logger('Fetched activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG); $result = self::process_delivery($arr['owner_xchan'], $AS, $arr, [$channel['channel_hash']], false, false, true, $force); if ($result) { $ret = array_merge($ret, $result); } + + $i++; } return $ret; -- cgit v1.2.3 From 4bc4f5b2a6507a09357c16d6e5f1c5ea928dbdb3 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 7 Feb 2024 15:56:54 +0000 Subject: update docu and remove redundant pernission check after vonv fetch fixes --- Zotlabs/Lib/Libzot.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 002ccedfc..12edafb8d 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1791,15 +1791,12 @@ class Libzot { // Conversation fetches (e.g. $request == true) take place for // a) new comments on expired posts // b) manual import of posts via search (in this case force will be true) - // c) import of conversations from friends of friends (those will currently only be accepted in the public stream) + // c) import of conversations from friends of friends (they can currently arriuve from streams if a channel is configured to do so) - // If it is a toplevel post check permissions for the item author instead of the sender (we might want to remove this if we want friend of friend posts in the network stream). // Comments of all these activities are allowed and will only be rejected (later) if the parent // doesn't exist. if ($perm === 'send_stream') { - $allowed = perm_is_allowed($channel['channel_id'], $arr['author_xchan'], $perm); - if ($force) { $allowed = true; } -- cgit v1.2.3 From 08884c44fb0ee68671a070a8b47aa16224d33881 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 8 Feb 2024 19:15:00 +0000 Subject: whitespace --- Zotlabs/Lib/Libzot.php | 2 -- 1 file changed, 2 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 12edafb8d..c062ff16b 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1783,8 +1783,6 @@ class Libzot { elseif ($permit_mentions) { $allowed = true; } - - } if ($request) { -- cgit v1.2.3 From 5fbc203367baffc65e631358478b5d6be5943999 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 8 Feb 2024 19:32:40 +0000 Subject: mark items verified in zot delivery also if either LDSignature or EddsaSignature verified --- Zotlabs/Lib/Libzot.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index c062ff16b..ba75d9fa9 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1284,7 +1284,7 @@ class Libzot { } } - if (isset($AS->meta['hubloc']) && $AS->meta['hubloc']) { + if (!empty($AS->meta['hubloc']) || $AS->sigok) { $item['item_verified'] = true; } @@ -2076,7 +2076,7 @@ class Libzot { // WARNING: the presence of both source_xchan and non-zero item_uplink here will cause a delivery loop $arr['item_uplink'] = 0; - if (isset($AS->meta['hubloc']) || $arr['author_xchan'] === $arr['owner_xchan']) { + if (!empty($AS->meta['hubloc']) || $arr['author_xchan'] === $arr['owner_xchan'] || $AS->sigok) { $arr['item_verified'] = true; } -- cgit v1.2.3 From 07978a061eeeea0e95a381dab821bbd7f43e85ea Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 13 Feb 2024 09:22:12 +0000 Subject: mb_strlen() will return 2 for some emojis - possibly grapheme_strlen() will be better for this job --- Zotlabs/Lib/Activity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index ddd91f60b..dc934c44c 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2189,7 +2189,7 @@ class Activity { $t = trim(self::get_textfield($act->data, 'content')); // Unicode emojis - if (mb_strlen($t) === 1) { + if (grapheme_strlen($t) === 1) { $content['content'] = $t; } // Custom emojis -- cgit v1.2.3 From 9291622885646ce9c5ebb4249d90f86f8b74205d Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 13 Feb 2024 10:48:06 +0000 Subject: fix logic so that direct messages will be allowed in case the send_mail permission is granted even if the send_stream permission is not granted --- Zotlabs/Lib/Activity.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index dc934c44c..020a87ea7 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2712,6 +2712,17 @@ class Activity { $item['owner_xchan'] = $observer_hash; } + // An ugly and imperfect way to recognise a mastodon direct message + if ( + $item['item_private'] === 1 && + !isset($act->raw_recips['cc']) && + is_array($act->raw_recips['to']) && + in_array(channel_url($channel), $act->raw_recips['to']) && + !in_array($act->actor['followers'], $act->raw_recips['to']) + ) { + $item['item_private'] = 2; + } + $allowed = false; $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system','permit_all_mentions') && i_am_mentioned($channel, $item)); @@ -2830,8 +2841,8 @@ class Activity { } if (intval($item['item_private']) === 2) { - if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'post_mail')) { - $allowed = false; + if (perm_is_allowed($channel['channel_id'], $observer_hash, 'post_mail')) { + $allowed = true; } } @@ -2978,17 +2989,6 @@ class Activity { } } - // An ugly and imperfect way to recognise a mastodon direct message - if ( - $item['item_private'] === 1 && - !isset($act->raw_recips['cc']) && - is_array($act->raw_recips['to']) && - in_array(channel_url($channel), $act->raw_recips['to']) && - !in_array($act->actor['followers'], $act->raw_recips['to']) - ) { - $item['item_private'] = 2; - } - // TODO: not implemented // self::rewrite_mentions($item); $r = q("select id, created, edited from item where mid = '%s' and uid = %d limit 1", -- cgit v1.2.3 From 060210e930e54ab7894c853dadc4978ad97b296b Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 13 Feb 2024 11:00:49 +0000 Subject: consider a message arriving to our inbox with no recipients (as seen from friendica) a direct message --- Zotlabs/Lib/Activity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 020a87ea7..08fd6ee05 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2601,7 +2601,7 @@ class Activity { $s['item_private'] = 0; } - if ($act->objprop('directMessage')) { + if ($act->objprop('directMessage') || empty($act->recips)) { $s['item_private'] = 2; } -- cgit v1.2.3 From 55236f86e06ded054a58c36e52b9a32a19affb46 Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 13 Feb 2024 11:19:28 +0000 Subject: move the empty recips check to store(). otherwise it might interfere with zot6 native addressing which is always empty --- Zotlabs/Lib/Activity.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 08fd6ee05..0f76fce9a 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2601,7 +2601,7 @@ class Activity { $s['item_private'] = 0; } - if ($act->objprop('directMessage') || empty($act->recips)) { + if ($act->objprop('directMessage')) { $s['item_private'] = 2; } @@ -2712,13 +2712,13 @@ class Activity { $item['owner_xchan'] = $observer_hash; } - // An ugly and imperfect way to recognise a mastodon direct message - if ( - $item['item_private'] === 1 && + // An ugly and imperfect way to recognise a mastodon or friendica direct message + if (empty($act->recips) || // friendica + ($item['item_private'] === 1 && !isset($act->raw_recips['cc']) && is_array($act->raw_recips['to']) && in_array(channel_url($channel), $act->raw_recips['to']) && - !in_array($act->actor['followers'], $act->raw_recips['to']) + !in_array($act->actor['followers'], $act->raw_recips['to'])) ) { $item['item_private'] = 2; } -- cgit v1.2.3 From 9a85421a0e0c9b8d0c29c57ad9888defcf9084e1 Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 13 Feb 2024 14:05:30 +0000 Subject: we are now using the item uuid for the notification hash if available. since we can have more than one notification per item (e.g. tag and comment) also look for the notification type to make sure we get the right one --- Zotlabs/Lib/Enotify.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index a9eaf3136..8a980519d 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -512,7 +512,7 @@ class Enotify { $datarray['link'] = $itemlink; $datarray['parent'] = $parent_mid; $datarray['parent_item'] = $parent_item; - $datarray['ntype'] = $params['type'] ?? ''; + $datarray['ntype'] = $params['type'] ?? 0; $datarray['verb'] = $params['verb'] ?? ''; $datarray['otype'] = $params['otype'] ?? ''; $datarray['abort'] = false; @@ -560,8 +560,9 @@ class Enotify { dbesc($datarray['otype']) ); - $r = q("select id from notify where hash = '%s' and uid = %d limit 1", + $r = q("select id from notify where hash = '%s' and ntype = %d and uid = %d limit 1", dbesc($datarray['hash']), + intval($datarray['ntype']), intval($recip['channel_id']) ); if ($r) { -- cgit v1.2.3 From 9859008271d1493ad600dff34a1d6e250378c496 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 14 Feb 2024 20:23:02 +0000 Subject: deal with inReplyTo array + some docu and style --- Zotlabs/Lib/ActivityStreams.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index b3b58af89..9f028bb46 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -89,7 +89,7 @@ class ActivityStreams { // Attempt to assemble an Activity from what we were given. if ($this->is_valid()) { - $this->id = $this->get_property_obj('id'); + $this->id = $this->get_property_obj('id'); if (!$this->id) { logger('Data with mmissing id: ' . print_r($this->data, true)); @@ -130,24 +130,31 @@ class ActivityStreams { } } - // fetch recursive or embedded activities + // Fetch recursive or embedded activities if ($this->obj && is_array($this->obj) && array_key_exists('object', $this->obj)) { $this->obj['object'] = $this->get_compound_property('object', $this->obj); } - if ($this->obj && is_array($this->obj) && isset($this->obj['actor'])) + // Enumerate and store actors in referenced objects + + if ($this->obj && is_array($this->obj) && isset($this->obj['actor'])) { $this->obj['actor'] = $this->get_actor('actor', $this->obj); - if ($this->tgt && is_array($this->tgt) && isset($this->tgt['actor'])) + } + + if ($this->tgt && is_array($this->tgt) && isset($this->tgt['actor'])) { $this->tgt['actor'] = $this->get_actor('actor', $this->tgt); + } + + // Determine if this is a followup or response activity $this->parent_id = $this->get_property_obj('inReplyTo'); - if (!$this->parent_id && is_array($this->obj) && isset($this->obj['inReplyTo'])) { - $this->parent_id = $this->obj['inReplyTo']; + if (!$this->parent_id && isset($this->obj['inReplyTo'])) { + $this->parent_id = ((is_array($this->obj['inReplyTo'])) ? $this->obj['inReplyTo']['id'] : $this->obj['inReplyTo']); } - if (!$this->parent_id && is_array($this->obj) && isset($this->obj['id'])) { + if (!$this->parent_id && isset($this->obj['id'])) { $this->parent_id = $this->obj['id']; } -- cgit v1.2.3 From 6d125d02d8cc6b09843919eb9413abbb85582c1e Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 15 Feb 2024 14:27:50 +0000 Subject: introduce get_actor() force flag to omit cache, rework contact refresh, special handling for announce by group, and revert change regarding friendica addressing anomality --- Zotlabs/Lib/Activity.php | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 0f76fce9a..ab96423d7 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1659,7 +1659,7 @@ class Activity { if ($ap_hubloc) { // we already have a stored record. Determine if it needs updating. if ($ap_hubloc['hubloc_updated'] < datetime_convert('UTC', 'UTC', ' now - 3 days') || $force) { - $person_obj = self::get_cached_actor($url); + $person_obj = self::get_actor($url, $force); } else { return; @@ -2370,6 +2370,7 @@ class Activity { } if (!$response_activity) { +/* if ($act->type === 'Announce') { $s['author_xchan'] = self::get_attributed_to_actor_url($act); $s['mid'] = $act->objprop('id') ?: $act->obj; @@ -2379,6 +2380,7 @@ class Activity { $s['parent_mid'] = $act->objprop('id') ?: $act->obj; } } +*/ // we will need a hook here to extract magnet links e.g. peertube // right now just link to the largest mp4 we find that will fit in our @@ -2713,12 +2715,12 @@ class Activity { } // An ugly and imperfect way to recognise a mastodon or friendica direct message - if (empty($act->recips) || // friendica - ($item['item_private'] === 1 && + if ( + $item['item_private'] === 1 && !isset($act->raw_recips['cc']) && is_array($act->raw_recips['to']) && in_array(channel_url($channel), $act->raw_recips['to']) && - !in_array($act->actor['followers'], $act->raw_recips['to'])) + !in_array($act->actor['followers'], $act->raw_recips['to']) ) { $item['item_private'] = 2; } @@ -3076,10 +3078,12 @@ class Activity { $p = []; $announce_init = false; + $group_announce_init = false; if (is_object($act) && is_array($item)) { $p[] = [$act, $item]; $announce_init = ($item['verb'] === 'Announce'); + $group_announce_init = ($announce_init && $act->actor['type'] === 'Group'); } if (is_string($item)) { @@ -3149,12 +3153,22 @@ class Activity { $item['source_xchan'] = $observer_hash; // WARNING: the presence of both source_xchan and non-zero item_uplink here will cause a delivery loop $item['item_uplink'] = 0; - $item['verb'] = 'Announce'; - $item['parent_mid'] = $item['thr_parent'] = $item['mid']; - $item['item_thread_top'] = 1; + + if ($item['item_thread_top']) { + $item['verb'] = 'Announce'; + } + + if (!$group_announce_init) { + // Force a new thread if the announce init actor is not a group + $item['verb'] = 'Announce'; + $item['parent_mid'] = $item['thr_parent'] = $item['mid']; + $item['item_thread_top'] = 1; + } + } else { $announce_init = ($i === 0 && $item['verb'] === 'Announce'); + $group_announce_init = ($announce_init && $a->actor['type'] === 'Group'); } if (intval($channel['channel_system']) && intval($item['item_private'])) { @@ -3483,11 +3497,11 @@ class Activity { return $hookdata['actor']; } - static function get_actor($actor_id) { + static function get_actor($actor_id, $force = false) { // remove fragment $actor_id = ((strpos($actor_id, '#')) ? substr($actor_id, 0, strpos($actor_id, '#')) : $actor_id); - $actor = self::get_cached_actor($actor_id); + $actor = ((!$force) ? self::get_cached_actor($actor_id) : null); if ($actor) { return $actor; -- cgit v1.2.3 From 17e2877c91dfc889ab5edb62fc6e00dd7dcbba01 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 21 Feb 2024 10:44:56 +0000 Subject: make sure to decode html special chars before sending over the wire and --- Zotlabs/Lib/Activity.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index ab96423d7..4db116b5e 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -517,7 +517,7 @@ class Activity { } if ($i['title']) - $ret['name'] = $i['title']; + $ret['name'] = unescape_tags($i['title']); $ret['published'] = datetime_convert('UTC', 'UTC', $i['created'], ATOM_TIME); if ($i['created'] !== $i['edited']) @@ -564,11 +564,11 @@ class Activity { if ($i['mimetype'] === 'text/bbcode') { if ($i['title']) - $ret['name'] = bbcode($i['title'], ['cache' => true]); + $ret['name'] = unescape_tags($i['title']); if ($i['summary']) - $ret['summary'] = bbcode($i['summary'], ['cache' => true]); - $ret['content'] = bbcode($i['body'], ['cache' => true]); - $ret['source'] = ['content' => $i['body'], 'mediaType' => 'text/bbcode']; + $ret['summary'] = unescape_tags($i['summary']); + $ret['content'] = bbcode(unescape_tags($i['body']), ['cache' => true]); + $ret['source'] = ['content' => unescape_tags($i['body']), 'mediaType' => 'text/bbcode']; } $actor = self::encode_person($i['author'], false); -- cgit v1.2.3 From b860b730a9fe718ad35cd918ab237afe42cf386c Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 22 Feb 2024 10:23:38 +0000 Subject: simplify pleroma custom emoji stuff and some cleanup --- Zotlabs/Lib/Activity.php | 71 ++++++++++++------------------------------------ 1 file changed, 17 insertions(+), 54 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 4db116b5e..9a76ccf2e 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -612,11 +612,12 @@ class Activity { if (!array_key_exists(0, $ptr)) { $ptr = [$ptr]; } + foreach ($ptr as $t) { if (is_array($t) && !array_key_exists('type', $t)) $t['type'] = 'Hashtag'; - if (is_array($t) && array_key_exists('href', $t) && array_key_exists('name', $t)) { + if (is_array($t) && (array_key_exists('href', $t) || array_key_exists('id', $t)) && array_key_exists('name', $t)) { switch ($t['type']) { case 'Hashtag': $ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])]; @@ -630,6 +631,10 @@ class Activity { $ret[] = ['ttype' => TERM_BOOKMARK, 'url' => $t['href'], 'term' => escape_tags($t['name'])]; break; + case 'Emoji': + $ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['icon']['url'], 'term' => escape_tags($t['name'])]; + break; + default: break; } @@ -1228,6 +1233,7 @@ class Activity { if (strpos($verb, ACTIVITY_REACT) !== false) return 'emojiReaction'; + if (strpos($verb, ACTIVITY_MOOD) !== false) return 'Create'; @@ -2184,7 +2190,7 @@ class Activity { $content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';'); } - if (in_array($act->type, ['EmojiReaction', 'EmojiReact'])) { + if (in_array($act->type, ['EmojiReact'])) { // Pleroma reactions $t = trim(self::get_textfield($act->data, 'content')); @@ -2192,14 +2198,15 @@ class Activity { if (grapheme_strlen($t) === 1) { $content['content'] = $t; } + // Custom emojis - elseif (preg_match('/^[:].*[:]$/i', $t, $match)) { - $content['content'] = $match[0]; - if (isset($act->data['tag']) && is_array($act->data['tag'])) { - foreach ($act->data['tag'] as $tag) { - if ($tag['type'] === 'Emoji' && $tag['name'] === trim($match[0], ':')) { - $content['content'] = '[img=32x32]' . $tag['id'] . '[/img]'; - } + $e = self::decode_taxonomy($act->data); + + if ($e) { + $s['term'] = $e; + foreach ($e as $ee) { + if ($ee['ttype'] === TERM_EMOJI) { + $content['content'] = '[img=32x32]' . $ee['url'] . '[/img]'; } } } @@ -2329,15 +2336,9 @@ class Activity { if (is_array($act->obj) && !$response_activity) { $a = self::decode_taxonomy($act->obj); + if ($a) { $s['term'] = $a; - foreach ($a as $b) { - if ($b['ttype'] === TERM_EMOJI) { - $s['title'] = str_replace($b['term'], '[img=16x16]' . $b['url'] . '[/img]', $s['title']); - $s['summary'] = str_replace($b['term'], '[img=16x16]' . $b['url'] . '[/img]', $s['summary']); - $s['body'] = str_replace($b['term'], '[img=16x16]' . $b['url'] . '[/img]', $s['body']); - } - } } $a = self::decode_attachment($act->obj); @@ -2370,17 +2371,6 @@ class Activity { } if (!$response_activity) { -/* - if ($act->type === 'Announce') { - $s['author_xchan'] = self::get_attributed_to_actor_url($act); - $s['mid'] = $act->objprop('id') ?: $act->obj; - - // Do not force new thread if the announce is from a group actor - if ($act->actor['type'] !== 'Group') { - $s['parent_mid'] = $act->objprop('id') ?: $act->obj; - } - } -*/ // we will need a hook here to extract magnet links e.g. peertube // right now just link to the largest mp4 we find that will fit in our @@ -2634,33 +2624,6 @@ class Activity { } } - // old style: can be removed after most hubs are on 7.0.2 - elseif (array_key_exists('signed', $raw_arr) && is_array($act->obj) && isset($act->data['attachment']) && is_array($act->obj['attachment'])) { - foreach($act->obj['attachment'] as $a) { - if ( - isset($a['type']) && $a['type'] === 'PropertyValue' && - isset($a['name']) && $a['name'] === 'zot.activitypub.rawmsg' && - isset($a['value']) - ) { - $ap_rawmsg = $a['value']; - } - - if ( - isset($a['type']) && $a['type'] === 'PropertyValue' && - isset($a['name']) && $a['name'] === 'zot.diaspora.fields' && - isset($a['value']) - ) { - $diaspora_rawmsg = $a['value']; - } - } - } - - // catch the likes - if (!$ap_rawmsg && $response_activity) { - $ap_rawmsg = json_encode($act->data, JSON_UNESCAPED_SLASHES); - } - // end old style - if (!$ap_rawmsg && array_key_exists('signed', $raw_arr)) { // zap $ap_rawmsg = json_encode($act->data, JSON_UNESCAPED_SLASHES); -- cgit v1.2.3 From 3dd739424718596b94f5a61d2015388db2491999 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 25 Feb 2024 19:29:50 +0000 Subject: AS2 --- Zotlabs/Lib/Activity.php | 142 +++++++------------------------------------ Zotlabs/Lib/Enotify.php | 12 ++-- Zotlabs/Lib/Libzot.php | 2 +- Zotlabs/Lib/Share.php | 2 +- Zotlabs/Lib/ThreadItem.php | 2 +- Zotlabs/Lib/ThreadStream.php | 2 +- 6 files changed, 31 insertions(+), 131 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 9a76ccf2e..844dc5905 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -27,19 +27,23 @@ class Activity { return $x['asld']; } - if ($x['type'] === ACTIVITY_OBJ_PERSON) { + if (in_array($x['type'], ['Person', ACTIVITY_OBJ_PERSON])) { return self::fetch_person($x); } - if ($x['type'] === ACTIVITY_OBJ_PROFILE) { + + if (in_array($x['type'], ['Profile', ACTIVITY_OBJ_PROFILE])) { return self::fetch_profile($x); } - if (in_array($x['type'], [ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE])) { + + if (in_array($x['type'], ['Note', 'Article', ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE])) { return self::fetch_item($x); } + if ($x['type'] === ACTIVITY_OBJ_THING) { return self::fetch_thing($x); } - if ($x['type'] === ACTIVITY_OBJ_EVENT) { + + if (in_array($x['type'], ['Event', ACTIVITY_OBJ_EVENT])) { return self::fetch_event($x); } @@ -224,7 +228,7 @@ class Activity { if ($r) { xchan_query($r, true); $r = fetch_post_tags($r); - if (in_array($r[0]['verb'], ['Create', 'Invite']) && $r[0]['obj_type'] === ACTIVITY_OBJ_EVENT) { + if (in_array($r[0]['verb'], ['Create', 'Invite']) && in_array($r[0]['obj_type'], ['Event', ACTIVITY_OBJ_EVENT])) { $r[0]['verb'] = 'Invite'; return self::encode_activity($r[0]); } @@ -936,7 +940,7 @@ class Activity { if (!is_array($i['obj'])) { $i['obj'] = json_decode($i['obj'], true); } - if ($i['obj']['type'] === ACTIVITY_OBJ_PHOTO) { + if (in_array($i['obj']['type'], ['Image', ACTIVITY_OBJ_PHOTO])) { $i['obj']['id'] = $i['mid']; } @@ -1174,7 +1178,7 @@ class Activity { if (!is_array($item[$elm])) { $item[$elm] = json_decode($item[$elm], true); } - if ($item[$elm]['type'] === ACTIVITY_OBJ_PHOTO) { + if (in_array($item[$elm]['type'], ['Image', ACTIVITY_OBJ_PHOTO])) { $item[$elm]['id'] = $item['mid']; } @@ -1208,19 +1212,13 @@ class Activity { 'http://activitystrea.ms/schema/1.0/like' => 'Like', 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', 'http://purl.org/zot/activity/dislike' => 'Dislike', - // 'http://activitystrea.ms/schema/1.0/tag' => 'Add', + //'http://activitystrea.ms/schema/1.0/tag' => 'Add', 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow', 'http://activitystrea.ms/schema/1.0/stop-following' => 'Unfollow', 'http://purl.org/zot/activity/attendyes' => 'Accept', 'http://purl.org/zot/activity/attendno' => 'Reject', 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept', - 'Announce' => 'Announce', - 'Invite' => 'Invite', - 'Delete' => 'Delete', - 'Undo' => 'Undo', - 'Add' => 'Add', - 'Remove' => 'Remove' ]; call_hooks('activity_mapper', $acts); @@ -1232,7 +1230,7 @@ class Activity { // Reactions will just map to normal activities if (strpos($verb, ACTIVITY_REACT) !== false) - return 'emojiReaction'; + return 'Create'; if (strpos($verb, ACTIVITY_MOOD) !== false) return 'Create'; @@ -1341,13 +1339,7 @@ class Activity { 'http://purl.org/zot/activity/tagterm' => 'zot:Tag', 'http://purl.org/zot/activity/thing' => 'Object', 'http://purl.org/zot/activity/file' => 'zot:File', - 'http://purl.org/zot/activity/mood' => 'zot:Mood', - 'Invite' => 'Invite', - 'Question' => 'Question', - 'Audio' => 'Audio', - 'Video' => 'Video', - 'Delete' => 'Delete', - 'Undo' => 'Undo' + 'http://purl.org/zot/activity/mood' => 'zot:Mood' ]; call_hooks('activity_obj_mapper', $objs); @@ -2256,7 +2248,7 @@ class Activity { $s['body'] .= $quote_bbcode; } - $s['verb'] = self::activity_decode_mapper($act->type); + $s['verb'] = self::activity_mapper($act->type); // Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here. if ($act->type === 'Update' && $act->objprop('type') === 'Question' && $s['edited'] === $s['created']) { @@ -2267,63 +2259,16 @@ class Activity { $s['item_deleted'] = 1; } - if (isset($act->obj['type'])) { - $s['obj_type'] = self::activity_obj_decode_mapper($act->obj['type']); - } - - if ($s['obj_type'] === ACTIVITY_OBJ_NOTE && $s['mid'] !== $s['parent_mid']) { - $s['obj_type'] = ACTIVITY_OBJ_COMMENT; + if ($act->objprop('type')) { + $s['obj_type'] = self::activity_obj_mapper($act->obj['type']); } $s['obj'] = $act->obj; + if (array_path_exists('actor/id', $s['obj'])) { $s['obj']['actor'] = $s['obj']['actor']['id']; } -/* - $eventptr = null; - - if ($act->obj['type'] === 'Invite' && array_path_exists('object/type', $act->obj) && $act->obj['object']['type'] === 'Event') { - $eventptr = $act->obj['object']; - $s['mid'] = $s['parent_mid'] = $act->obj['id']; - } - - if ($act->obj['type'] === 'Event') { - if ($act->type === 'Invite') { - $s['mid'] = $s['parent_mid'] = $act->id; - } - $eventptr = $act->obj; - } - - if ($eventptr) { - - $s['obj'] = []; - $s['obj']['asld'] = $eventptr; - $s['obj']['type'] = ACTIVITY_OBJ_EVENT; - $s['obj']['id'] = $eventptr['id']; - $s['obj']['title'] = html2plain($eventptr['name']); - - if (strpos($act->obj['startTime'], 'Z')) - $s['obj']['adjust'] = true; - else - $s['obj']['adjust'] = true; - - $s['obj']['dtstart'] = datetime_convert('UTC', 'UTC', $eventptr['startTime']); - if ($act->obj['endTime']) - $s['obj']['dtend'] = datetime_convert('UTC', 'UTC', $eventptr['endTime']); - else - $s['obj']['nofinish'] = true; - $s['obj']['description'] = html2bbcode($eventptr['content']); - - if (array_path_exists('location/content', $eventptr)) - $s['obj']['location'] = $eventptr['location']['content']; - - } - else { - $s['obj'] = $act->obj; - } -*/ - $generator = $act->get_property_obj('generator'); if ((!$generator) && (!$response_activity)) { $generator = $act->get_property_obj('generator', $act->obj); @@ -2715,16 +2660,13 @@ class Activity { return; } - - // TODO: if we do not have a parent stop here and move the fetch to background? - - if ($parent && $parent[0]['obj_type'] === 'Question') { - if ($item['obj_type'] === ACTIVITY_OBJ_COMMENT && $item['title'] && (!$item['body'])) { + if ($parent[0]['obj_type'] === 'Question') { + if (in_array($item['obj_type'], ['Note', ACTIVITY_OBJ_COMMENT]) && $item['title'] && (!$item['body'])) { $item['obj_type'] = 'Answer'; } } - if ($parent && $parent[0]['item_wall']) { + if ($parent[0]['item_wall']) { // set the owner to the owner of the parent $item['owner_xchan'] = $parent[0]['owner_xchan']; @@ -3313,49 +3255,7 @@ class Activity { $event['nofinish'] = true; } } -/* - $eventptr = null; - - if ($act->obj['type'] === 'Invite' && array_path_exists('object/type', $act->obj) && $act->obj['object']['type'] === 'Event') { - $eventptr = $act->obj['object']; - $s['mid'] = $s['parent_mid'] = $act->obj['id']; - } - if ($act->obj['type'] === 'Event') { - if ($act->type === 'Invite') { - $s['mid'] = $s['parent_mid'] = $act->id; - } - $eventptr = $act->obj; - } - - if ($eventptr) { - - $s['obj'] = []; - $s['obj']['asld'] = $eventptr; - $s['obj']['type'] = ACTIVITY_OBJ_EVENT; - $s['obj']['id'] = $eventptr['id']; - $s['obj']['title'] = html2plain($eventptr['name']); - - if (strpos($act->obj['startTime'], 'Z')) - $s['obj']['adjust'] = true; - else - $s['obj']['adjust'] = true; - - $s['obj']['dtstart'] = datetime_convert('UTC', 'UTC', $eventptr['startTime']); - if ($act->obj['endTime']) - $s['obj']['dtend'] = datetime_convert('UTC', 'UTC', $eventptr['endTime']); - else - $s['obj']['nofinish'] = true; - $s['obj']['description'] = html2bbcode($eventptr['content']); - - if (array_path_exists('location/content', $eventptr)) - $s['obj']['location'] = $eventptr['location']['content']; - - } - else { - $s['obj'] = $act->obj; - } -*/ foreach (['name', 'summary', 'content'] as $a) { if (($x = self::get_textfield($act, $a)) !== false) { $content[$a] = $x; diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index 8a980519d..48a255e95 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -149,7 +149,7 @@ class Enotify { if(array_key_exists('item',$params)) { - if(in_array($params['item']['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_SHARE])) { + if(in_array($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_SHARE])) { if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE)) { logger('notification: not a visible activity. Ignoring.'); @@ -157,10 +157,10 @@ class Enotify { return; } - if(activity_match($params['verb'], ACTIVITY_LIKE)) + if(activity_match($params['verb'], ['Like', ACTIVITY_LIKE])) $action = (($moderated) ? t('requested to like') : t('liked')); - if(activity_match($params['verb'], ACTIVITY_DISLIKE)) + if(activity_match($params['verb'], ['Dislike', ACTIVITY_DISLIKE])) $action = (($moderated) ? t('requested to dislike') : t('disliked')); if(activity_match($params['verb'], ACTIVITY_SHARE)) @@ -262,7 +262,7 @@ class Enotify { $itemlink = $params['link']; - if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ACTIVITY_LIKE) || activity_match($params['item']['verb'], ACTIVITY_DISLIKE))) { + if (array_key_exists('item',$params) && (activity_match($params['item']['verb'], ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE]))) { if(! $always_show_in_notices || !($vnotify & VNOTIFY_LIKE) || !feature_enabled($recip['channel_id'], 'dislike')) { logger('notification: not a visible activity. Ignoring.'); pop_lang(); @@ -313,10 +313,10 @@ class Enotify { //$verb = ((activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) ? t('disliked') : t('liked')); $moderated = (($params['item']['item_blocked'] == ITEM_MODERATED) ? true : false); - if(activity_match($params['item']['verb'], ACTIVITY_LIKE)) + if(activity_match($params['item']['verb'], ['Like', ACTIVITY_LIKE])) $verb = (($moderated) ? t('requested to like') : t('liked')); - if(activity_match($params['item']['verb'], ACTIVITY_DISLIKE)) + if(activity_match($params['item']['verb'], ['Dislike', ACTIVITY_DISLIKE])) $verb = (($moderated) ? t('requested to dislike') : t('disliked')); // "your post" diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index ba75d9fa9..a98ae8f20 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1699,7 +1699,7 @@ class Libzot { // route checking doesn't work correctly here because we've changed the privacy $parent[0]['route'] = EMPTY_STR; // If this is a poll response, convert the obj_type to our (internal-only) "Answer" type - if ($arr['obj_type'] === ACTIVITY_OBJ_COMMENT && $arr['title'] && (!$arr['body'])) { + if (in_array($arr['obj_type'], ['Note', ACTIVITY_OBJ_COMMENT]) && $arr['title'] && (!$arr['body'])) { $arr['obj_type'] = 'Answer'; } } diff --git a/Zotlabs/Lib/Share.php b/Zotlabs/Lib/Share.php index 81f378d0d..8abbfda80 100644 --- a/Zotlabs/Lib/Share.php +++ b/Zotlabs/Lib/Share.php @@ -112,7 +112,7 @@ class Share { if(! $this->item) return $bb; - $is_photo = (($this->item['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false); + $is_photo = ((in_array($this->item['obj_type'], ['Image', ACTIVITY_OBJ_PHOTO])) ? true : false); if($is_photo) { $object = json_decode($this->item['obj'],true); $photo_bb = $object['body']; diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 6b07e32e9..42d76bf17 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -643,7 +643,7 @@ class ThreadItem { * Only add what will be displayed */ - if(activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE)) { + if(activity_match($item->get_data_value('verb'), ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE])) { return false; } diff --git a/Zotlabs/Lib/ThreadStream.php b/Zotlabs/Lib/ThreadStream.php index 72d2bd2f8..fb3b6dd9b 100644 --- a/Zotlabs/Lib/ThreadStream.php +++ b/Zotlabs/Lib/ThreadStream.php @@ -171,7 +171,7 @@ class ThreadStream { */ - if(($item->get_data_value('id') != $item->get_data_value('parent')) && (activity_match($item->get_data_value('verb'),ACTIVITY_LIKE) || activity_match($item->get_data_value('verb'),ACTIVITY_DISLIKE))) { + if($item->get_data_value('id') != $item->get_data_value('parent') && activity_match($item->get_data_value('verb'), ['Like', 'Dislike', ACTIVITY_LIKE, ACTIVITY_DISLIKE])) { return false; } -- cgit v1.2.3 From b4f079c4b51d4b4918b1901ee351bc40aeb343da Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 27 Feb 2024 10:31:27 +0000 Subject: For now we will use standard Create verb for emoji reactions --- Zotlabs/Lib/Activity.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 844dc5905..6b2c4d58a 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -1227,11 +1227,6 @@ class Activity { return $acts[$verb]; } - // Reactions will just map to normal activities - - if (strpos($verb, ACTIVITY_REACT) !== false) - return 'Create'; - if (strpos($verb, ACTIVITY_MOOD) !== false) return 'Create'; @@ -2178,6 +2173,7 @@ class Activity { $content['content'] = sprintf(t('🔁 Repeated %1$s\'s %2$s'), $mention, $act->obj['type']); } + // TODO: Deprecated if ($act->type === 'emojiReaction') { $content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';'); } -- cgit v1.2.3 From 37878bf0a35bcd0fc799892618a8b34ca0440c2c Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 28 Feb 2024 09:18:31 +0000 Subject: do away with deprecated activity types --- Zotlabs/Lib/Activity.php | 14 +------------- Zotlabs/Lib/Apps.php | 2 -- 2 files changed, 1 insertion(+), 15 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 6b2c4d58a..15e292ec4 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -448,13 +448,7 @@ class Activity { $ret = []; - if ($i['verb'] === ACTIVITY_FRIEND) { - // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note - $objtype = 'Note'; - } - else { - $objtype = self::activity_obj_mapper($i['obj_type']); - } + $objtype = self::activity_obj_mapper($i['obj_type']); if (intval($i['item_deleted'])) { $ret['type'] = 'Tombstone'; @@ -1227,15 +1221,9 @@ class Activity { return $acts[$verb]; } - if (strpos($verb, ACTIVITY_MOOD) !== false) - return 'Create'; - if (strpos($verb, ACTIVITY_FRIEND) !== false) return 'Create'; - if (strpos($verb, ACTIVITY_POKE) !== false) - return 'Activity'; - // We should return false, however this will trigger an uncaught execption and crash // the delivery system if encountered by the JSON-LDSignature library diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php index 00e65479e..1c05d69b1 100644 --- a/Zotlabs/Lib/Apps.php +++ b/Zotlabs/Lib/Apps.php @@ -352,8 +352,6 @@ class Apps { 'Directory' => t('Directory'), 'Help' => t('Help'), 'Mail' => t('Mail'), - 'Mood' => t('Mood'), - 'Poke' => t('Poke'), 'Chat' => t('Chat'), 'Search' => t('Search'), 'Probe' => t('Probe'), -- cgit v1.2.3 From 291e12574aeb3b71200b23d8ffc630a36f170008 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 28 Feb 2024 13:16:47 +0000 Subject: more cleanup --- Zotlabs/Lib/Activity.php | 8 -------- 1 file changed, 8 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 15e292ec4..b4ce4b5d0 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -783,11 +783,6 @@ class Activity { $ret = []; $reply = false; - if ($i['verb'] === ACTIVITY_FRIEND) { - // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note - $ret['obj'] = []; - } - $ret['type'] = self::activity_mapper($i['verb']); if ((isset($i['item_deleted']) && intval($i['item_deleted'])) && !$recurse) { @@ -1221,9 +1216,6 @@ class Activity { return $acts[$verb]; } - if (strpos($verb, ACTIVITY_FRIEND) !== false) - return 'Create'; - // We should return false, however this will trigger an uncaught execption and crash // the delivery system if encountered by the JSON-LDSignature library -- cgit v1.2.3 From 46f67eaa1e40954267088ba67726adc0d389628c Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 29 Feb 2024 17:05:48 +0000 Subject: AS2 Update and implement a first draft of AS2 Profile activities --- Zotlabs/Lib/Activity.php | 27 +++++++++++++++++++++------ Zotlabs/Lib/Libzot.php | 1 - 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index b4ce4b5d0..eef4f8036 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -172,10 +172,6 @@ class Activity { } static function fetch_person($x) { - return self::fetch_profile($x); - } - - static function fetch_profile($x) { $r = q("select * from xchan where xchan_url = '%s' limit 1", dbesc($x['id']) ); @@ -189,7 +185,14 @@ class Activity { return []; return self::encode_person($r[0]); + } + + static function fetch_profile($x) { + if (isset($x['describes'])) { + return $x; + } + return []; } static function fetch_thing($x) { @@ -978,6 +981,7 @@ class Activity { $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; } + $hookinfo = [ 'item' => $i, 'encoded' => $ret @@ -2049,6 +2053,10 @@ class Activity { $s['mid'] = $act->obj['data']['id']; } + if ($act->objprop('type') === 'Profile') { + $s['mid'] = $act->id; + } + if (!$s['mid']) { return false; } @@ -2293,6 +2301,14 @@ class Activity { if (!$response_activity) { + if ($act->objprop('type') === 'Profile') { + $s['parent_mid'] = $s['mid']; + $s['item_thread_top'] = 1; + $s['summary'] = ''; + $s['body'] = self::bb_content($content, 'summary'); + } + + // we will need a hook here to extract magnet links e.g. peertube // right now just link to the largest mp4 we find that will fit in our // standard content region @@ -2438,7 +2454,6 @@ class Activity { } } - if ($act->objprop('type') === 'Page' && !$s['body']) { $ptr = null; @@ -2479,7 +2494,7 @@ class Activity { } } - if (in_array($act->objprop('type', ''), ['Note', 'Article', 'Page'])) { + if (in_array($act->objprop('type'), ['Note', 'Article', 'Page'])) { $ptr = null; if (array_key_exists('url', $act->obj)) { diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index a98ae8f20..942c3082a 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1143,7 +1143,6 @@ class Libzot { if ($env['encoding'] === 'activitystreams') { $AS = new ActivityStreams($data); - if (!$AS->is_valid()) { logger('Activity rejected: ' . print_r($data, true)); return; -- cgit v1.2.3 From 8435d9eb1305d9678ef730c5a4924769b830e7d2 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 29 Feb 2024 17:35:05 +0000 Subject: some cleanup --- Zotlabs/Lib/Activity.php | 2 -- 1 file changed, 2 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index eef4f8036..1e0ce6ae2 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2304,8 +2304,6 @@ class Activity { if ($act->objprop('type') === 'Profile') { $s['parent_mid'] = $s['mid']; $s['item_thread_top'] = 1; - $s['summary'] = ''; - $s['body'] = self::bb_content($content, 'summary'); } -- cgit v1.2.3 From d7ceb977daec6aa07ba3a8e4bbc1d493d59509d1 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 4 Mar 2024 21:24:21 +0000 Subject: basic AS2 support for things --- Zotlabs/Lib/Activity.php | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 1e0ce6ae2..fb92e6398 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -205,14 +205,27 @@ class Activity { if (!$r) return []; + $channel = channelx_by_n($r[0]['obj_channel']); + + $content = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl] '; + $content .= $r[0]['obj_verb'] . ' '; + $content .= '[zrl=' . $r[0]['obj_url'] . ']' . $r[0]['obj_term'] . '[/zrl]'; + $x = [ - 'type' => 'Object', + 'type' => 'Page', 'id' => z_root() . '/thing/' . $r[0]['obj_obj'], - 'name' => $r[0]['obj_term'] + 'name' => $r[0]['obj_term'], + 'content' => bbcode($content), + 'url' => $r[0]['obj_url'] ]; - if ($r[0]['obj_image']) - $x['image'] = $r[0]['obj_image']; + if ($r[0]['obj_image']) { + $x['icon'] = [ + 'type' => 'Image', + 'url' => $r[0]['obj_image'] + + ]; + } return $x; -- cgit v1.2.3 From d23ed6b11fd44be6d5764f792f3ae01882405149 Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 5 Mar 2024 09:45:49 +0000 Subject: improve things display a little --- Zotlabs/Lib/Activity.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index fb92e6398..0275c87ac 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -207,23 +207,19 @@ class Activity { $channel = channelx_by_n($r[0]['obj_channel']); - $content = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl] '; - $content .= $r[0]['obj_verb'] . ' '; - $content .= '[zrl=' . $r[0]['obj_url'] . ']' . $r[0]['obj_term'] . '[/zrl]'; - $x = [ 'type' => 'Page', 'id' => z_root() . '/thing/' . $r[0]['obj_obj'], - 'name' => $r[0]['obj_term'], - 'content' => bbcode($content), + 'name' => $channel['channel_name'] . ' ' . $r[0]['obj_verb'] . ' ' . $r[0]['obj_term'], + 'content' => $r[0]['obj_url'], 'url' => $r[0]['obj_url'] ]; - if ($r[0]['obj_image']) { + if ($r[0]['obj_imgurl']) { + $x['content'] = '' . $r[0]['obj_term'] . ''; $x['icon'] = [ 'type' => 'Image', - 'url' => $r[0]['obj_image'] - + 'url' => $r[0]['obj_imgurl'] ]; } -- cgit v1.2.3 From 3c88c5e66aaf45015726b86c4127266ee073e8e4 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 6 Mar 2024 13:02:22 +0000 Subject: cleanup context and introduce schema:identifier for future use --- Zotlabs/Lib/Activity.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 0275c87ac..4c89e22bd 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3535,21 +3535,17 @@ class Activity { 'schema' => 'http://schema.org#', 'ostatus' => 'http://ostatus.org#', 'diaspora' => 'https://diasporafoundation.org/ns/', + 'litepub' => 'http://litepub.social/ns#', 'commentPolicy' => 'zot:commentPolicy', - 'locationAddress' => 'zot:locationAddress', - 'locationPrimary' => 'zot:locationPrimary', - 'locationDeleted' => 'zot:locationDeleted', - 'nomadicLocation' => 'zot:nomadicLocation', - 'nomadicHubs' => 'zot:nomadicHubs', - 'emojiReaction' => 'zot:emojiReaction', - 'expires' => 'zot:expires', - 'directMessage' => 'zot:directMessage', 'Bookmark' => 'zot:Bookmark', 'Category' => 'zot:Category', + 'directMessage' => 'litepub:directMessage', + 'PropertyValue' => 'schema:PropertyValue', 'value' => 'schema:value', + 'uuid' => 'schema:identifier', 'conversation' => 'ostatus:conversation', -- cgit v1.2.3 From 6262d351b777443bee2a1b5b534082268ebe72f9 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 7 Mar 2024 10:00:02 +0100 Subject: fix deprecation warning and add test --- Zotlabs/Lib/Activity.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 4c89e22bd..3af6253f9 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3282,17 +3282,18 @@ class Activity { return $content; } - static function get_textfield($act, $field) { + static function get_textfield($act, $field): null|string|array { + $content = null; - $content = false; - - if (array_key_exists($field, $act) && $act[$field]) + if (array_key_exists($field, $act) && $act[$field]) { $content = purify_html($act[$field]); + } elseif (array_key_exists($field . 'Map', $act) && $act[$field . 'Map']) { foreach ($act[$field . 'Map'] as $k => $v) { $content[escape_tags($k)] = purify_html($v); } } + return $content; } -- cgit v1.2.3 From 9e8ba5f6e24d4fdd1e06350f69731aaac9425948 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 7 Mar 2024 10:16:35 +0000 Subject: add at the top to maintain original order --- Zotlabs/Lib/Activity.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 3af6253f9..45cb1d803 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -608,9 +608,9 @@ class Activity { call_hooks('encode_item', $hookinfo); - return $hookinfo['encoded']; + } static function decode_taxonomy($item) { @@ -780,7 +780,7 @@ class Activity { $entry['image'] = $att['image']; } if ($entry) { - $ret[] = $entry; + array_unshift($ret, $entry); } } } elseif (isset($item['attachment']) && is_string($item['attachment'])) { -- cgit v1.2.3 From 45b1be8962903868c5d3a5e98ff09bd74bbecc85 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 8 Mar 2024 08:42:50 +0000 Subject: inbound support for custom emojis --- Zotlabs/Lib/Activity.php | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 45cb1d803..29b99fab5 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2183,18 +2183,6 @@ class Activity { if (grapheme_strlen($t) === 1) { $content['content'] = $t; } - - // Custom emojis - $e = self::decode_taxonomy($act->data); - - if ($e) { - $s['term'] = $e; - foreach ($e as $ee) { - if ($ee['ttype'] === TERM_EMOJI) { - $content['content'] = '[img=32x32]' . $ee['url'] . '[/img]'; - } - } - } } } @@ -2894,8 +2882,17 @@ class Activity { } } + if (!PConfig::Get($channel['channel_id'], 'system', 'no_smilies')) { + foreach ($item['term'] as $t) { + if ($t['ttype'] === TERM_EMOJI) { + $item['body'] = str_replace($t['term'], '[img class="smiley emoji custom-emoji" alt="' . $t['term'] . '" title="' . $t['term'] . '"]' . $t['url'] . '[/img]', $item['body']); + } + } + } + // TODO: not implemented // self::rewrite_mentions($item); + $r = q("select id, created, edited from item where mid = '%s' and uid = %d limit 1", dbesc($item['mid']), intval($item['uid']) -- cgit v1.2.3 From 043e2ff58bb98a8901d5c60bcfed9d380e395199 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 8 Mar 2024 09:23:31 +0000 Subject: check if term is set before processing it --- Zotlabs/Lib/Activity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 29b99fab5..43f7386e7 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2882,7 +2882,7 @@ class Activity { } } - if (!PConfig::Get($channel['channel_id'], 'system', 'no_smilies')) { + if (isset($item['term']) && !PConfig::Get($channel['channel_id'], 'system', 'no_smilies')) { foreach ($item['term'] as $t) { if ($t['ttype'] === TERM_EMOJI) { $item['body'] = str_replace($t['term'], '[img class="smiley emoji custom-emoji" alt="' . $t['term'] . '" title="' . $t['term'] . '"]' . $t['url'] . '[/img]', $item['body']); -- cgit v1.2.3 From ba1e705c6154d347000ab6c92ef59f7f6f60e886 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 8 Mar 2024 10:28:48 +0000 Subject: passing null to mb_strlen() is deprecated --- Zotlabs/Lib/Libzot.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 942c3082a..3495ede06 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -1890,12 +1890,12 @@ class Libzot { $maxlen = get_max_import_size(); - if ($maxlen && mb_strlen($arr['body']) > $maxlen) { + if ($maxlen && isset($arr['body']) && mb_strlen($arr['body']) > $maxlen) { $arr['body'] = mb_substr($arr['body'], 0, $maxlen, 'UTF-8'); logger('message length exceeds max_import_size: truncated'); } - if ($maxlen && mb_strlen($arr['summary']) > $maxlen) { + if ($maxlen && isset($arr['summary']) && mb_strlen($arr['summary']) > $maxlen) { $arr['summary'] = mb_substr($arr['summary'], 0, $maxlen, 'UTF-8'); logger('message summary length exceeds max_import_size: truncated'); } -- cgit v1.2.3 From 46fa26502b285213f3438abb1e3bd1482eb55bf5 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 9 Mar 2024 20:53:18 +0000 Subject: more work on emojis --- Zotlabs/Lib/Activity.php | 27 ++++++++++++++++++++++++--- Zotlabs/Lib/ThreadItem.php | 2 +- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 43f7386e7..e19499c56 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -642,7 +642,7 @@ class Activity { break; case 'Emoji': - $ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['icon']['url'], 'term' => escape_tags($t['name'])]; + $ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['id'], 'term' => escape_tags($t['name']), 'imgurl' => $t['icon']['url']]; break; default: @@ -677,6 +677,10 @@ class Activity { $ret[] = ['type' => 'Bookmark', 'href' => $t['url'], 'name' => $t['term']]; break; + case TERM_EMOJI: + $ret[] = ['type' => 'Emoji', 'id' => $t['url'], 'name' => $t['term'], 'icon' => ['type' => 'Image', 'url' => $t['imgurl']]]; + break; + default: break; } @@ -976,10 +980,12 @@ class Activity { return []; } +/* this should not be needed $t = self::encode_taxonomy($i); if ($t) { $ret['tag'] = $t; } +*/ $a = self::encode_attachment($i, true); if ($a) { @@ -997,6 +1003,7 @@ class Activity { ]; call_hooks('encode_activity', $hookinfo); + return $hookinfo['encoded']; } @@ -2179,9 +2186,17 @@ class Activity { // Pleroma reactions $t = trim(self::get_textfield($act->data, 'content')); + $content['content'] = $t; + // Unicode emojis if (grapheme_strlen($t) === 1) { - $content['content'] = $t; + $content['content'] = '

' . $t . '

'; + } + + $a = self::decode_taxonomy($act->data); + + if ($a) { + $s['term'] = $a; } } } @@ -2885,7 +2900,13 @@ class Activity { if (isset($item['term']) && !PConfig::Get($channel['channel_id'], 'system', 'no_smilies')) { foreach ($item['term'] as $t) { if ($t['ttype'] === TERM_EMOJI) { - $item['body'] = str_replace($t['term'], '[img class="smiley emoji custom-emoji" alt="' . $t['term'] . '" title="' . $t['term'] . '"]' . $t['url'] . '[/img]', $item['body']); + $class = 'emoji'; + $shortname = ':' . trim($t['term'], ':') . ':'; + if (is_solo_string($shortname, $item['body'])) { + $class .= ' single-emoji'; + } + + $item['body'] = str_replace($shortname, '[img class="' . $class . '" alt="' . $t['term'] . '" title="' . $t['term'] . '"]' . ($t['imgurl'] ?: $t['url']) . '[/img]', $item['body']); } } } diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 42d76bf17..8f364e945 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -19,7 +19,7 @@ class ThreadItem { private $comment_box_template = 'comment_item.tpl'; private $commentable = false; // list of supported reaction emojis - a site can over-ride this via config system.reactions - private $reactions = ['1f60a','1f44f','1f37e','1f48b','1f61e','2665','1f606','1f62e','1f634','1f61c','1f607','1f608']; + private $reactions = ['slightly_smiling_face','clapping_hands','bottle_with_popping_cork','kiss_mark','disappointed_face','red_heart','grinning_face','astonished_face','sleeping_face','winking_face_with_tongue','smiling_face_with_halo','smiling_face_with_horns']; private $toplevel = false; private $children = array(); private $parent = null; -- cgit v1.2.3 From d285da09fe59bf9269c0364964339b0f522b58c3 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 10 Mar 2024 13:12:51 +0100 Subject: add the file --- Zotlabs/Lib/Text.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Zotlabs/Lib/Text.php (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Text.php b/Zotlabs/Lib/Text.php new file mode 100644 index 000000000..a4dea90b9 --- /dev/null +++ b/Zotlabs/Lib/Text.php @@ -0,0 +1,24 @@ + Date: Sun, 10 Mar 2024 13:14:10 +0100 Subject: remove superfluous () --- Zotlabs/Lib/Text.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Text.php b/Zotlabs/Lib/Text.php index a4dea90b9..f593f9dd6 100644 --- a/Zotlabs/Lib/Text.php +++ b/Zotlabs/Lib/Text.php @@ -18,7 +18,7 @@ class Text { return EMPTY_STR; } - return (htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false)); + return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false); } } -- cgit v1.2.3 From 328ce0a837f596ef53895e272301aff3c2f7c84e Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 13 Mar 2024 14:05:58 +0100 Subject: fix another regression from last Lib/Config refactor which returned the default falue in case the value was an array. also add a testcase for this situation --- Zotlabs/Lib/Config.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Config.php b/Zotlabs/Lib/Config.php index 933f4bff3..95df8ed6f 100644 --- a/Zotlabs/Lib/Config.php +++ b/Zotlabs/Lib/Config.php @@ -143,6 +143,9 @@ class Config { return $value; } } + else { + return $value; + } } return $default; -- cgit v1.2.3 From b7bda0b87d1884b2b2b98f7d4ec00890311fc156 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 14 Mar 2024 09:47:08 +0000 Subject: return false if we have nothing to look at --- Zotlabs/Lib/Activity.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index e19499c56..bb08ab48e 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3190,6 +3190,10 @@ class Activity { public static function media_not_in_body($s, $body) { + if (empty($body)) { + return false; + } + $s_alt = htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); if ( -- cgit v1.2.3 From 42696606e3249da7d9273b9c8c504910f5fc28b5 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 14 Mar 2024 16:03:02 +0000 Subject: wrong logic --- Zotlabs/Lib/Activity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index bb08ab48e..f6ceaeca9 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3191,7 +3191,7 @@ class Activity { public static function media_not_in_body($s, $body) { if (empty($body)) { - return false; + return true; } $s_alt = htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); -- cgit v1.2.3 From 39d4f6741786ca2ed6dc631f94aa4a00279a0eb9 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 17 Mar 2024 10:53:09 +0000 Subject: add Emoji to the AP schema --- Zotlabs/Lib/Activity.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index f6ceaeca9..603155e7c 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -3559,10 +3559,12 @@ class Activity { 'ostatus' => 'http://ostatus.org#', 'diaspora' => 'https://diasporafoundation.org/ns/', 'litepub' => 'http://litepub.social/ns#', + 'toot' => 'http://joinmastodon.org/ns#', 'commentPolicy' => 'zot:commentPolicy', 'Bookmark' => 'zot:Bookmark', 'Category' => 'zot:Category', + 'Emoji' => 'toot:Emoji', 'directMessage' => 'litepub:directMessage', -- cgit v1.2.3 From edf898d7b701d9664f463adb97db9ca0f6293e1a Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 20 Mar 2024 19:33:50 +0000 Subject: it appears the smallest size for pt videos is now 720 --- Zotlabs/Lib/Activity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Zotlabs/Lib') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index 603155e7c..75d2ffbe9 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -2391,7 +2391,7 @@ class Activity { if ($mps) { usort($mps,[ '\Zotlabs\Lib\Activity', 'vid_sort' ]); foreach ($mps as $m) { - if (intval($m['height']) < 500 && self::media_not_in_body($m['href'],$s['body'])) { + if (intval($m['height']) <= 720 && self::media_not_in_body($m['href'],$s['body'])) { $s['body'] = $tag . $m['href'] . '[/video]' . "\r\n" . $s['body']; break; } -- cgit v1.2.3