From 85db7168943cb5ed3fbb9ab123e4c1116837922d Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Fri, 9 Dec 2022 16:24:37 -0500 Subject: [PATCH 01/21] Fix wrong condition when redirecting to filtered log view in admin/logs - Address https://friendica.xyz/display/adf174d5-1563-937d-3cd7-2df680918252 --- view/theme/frio/js/module/admin/logs/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/theme/frio/js/module/admin/logs/view.js b/view/theme/frio/js/module/admin/logs/view.js index 9faf9ec89..ab07882d2 100644 --- a/view/theme/frio/js/module/admin/logs/view.js +++ b/view/theme/frio/js/module/admin/logs/view.js @@ -6,7 +6,7 @@ $(function(){ var value = this.dataset.filterValue; var re = RegExp(filter+"=[a-z]*"); var newhref = location.href; - if (!location.href.indexOf("?") < 0) { + if (location.href.indexOf("?") < 0) { newhref = location.href + "?" + filter + "=" + value; } else if (location.href.match(re)) { newhref = location.href.replace(RegExp(filter+"=[a-z]*"), filter+"="+value); From 019bb56668e6c41254b851e2274be0f5c6cf79ea Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 10 Dec 2022 12:08:55 +0000 Subject: [PATCH 02/21] Issue 12373: Fix communication to Diaspora --- src/Model/Contact.php | 4 ++++ src/Network/Probe.php | 15 +++++++++++++++ src/Protocol/Diaspora.php | 13 ++++++++++--- src/Worker/Delivery.php | 2 +- src/Worker/Notifier.php | 2 +- 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/Model/Contact.php b/src/Model/Contact.php index e80f0752e..873de0890 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1396,6 +1396,8 @@ class Contact if ($data['network'] == Protocol::DIASPORA) { DI::dsprContact()->updateFromProbeArray($data); + } elseif (!empty($data['networks'][Protocol::DIASPORA])) { + DI::dsprContact()->updateFromProbeArray($data['networks'][Protocol::DIASPORA]); } self::updateFromProbeArray($contact_id, $data); @@ -2487,6 +2489,8 @@ class Contact if ($ret['network'] == Protocol::DIASPORA) { DI::dsprContact()->updateFromProbeArray($ret); + } elseif (!empty($ret['networks'][Protocol::DIASPORA])) { + DI::dsprContact()->updateFromProbeArray($ret['networks'][Protocol::DIASPORA]); } return self::updateFromProbeArray($id, $ret); diff --git a/src/Network/Probe.php b/src/Network/Probe.php index d79cd4055..9cdcd5fa8 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -134,6 +134,13 @@ class Probe } } + $newdata['networks'] = $data['networks'] ?? []; + foreach ([Protocol::DIASPORA, Protocol::OSTATUS] as $network) { + if (empty($newdata['networks'][$network])) { + unset($newdata['networks'][$network]); + } + } + // We don't use the "priority" field anymore and replace it with a dummy. $newdata['priority'] = 0; @@ -345,7 +352,11 @@ class Probe $data = []; } if (empty($data) || (!empty($ap_profile) && empty($network) && (($data['network'] ?? '') != Protocol::DFRN))) { + $networks = $data['networks'] ?? []; + unset($data['networks']); + $networks[$data['network']] = $data; $data = $ap_profile; + $data['networks'] = $networks; } elseif (!empty($ap_profile)) { $ap_profile['batch'] = ''; $data = array_merge($ap_profile, $data); @@ -716,9 +727,13 @@ class Probe } if ((!$result && ($network == '')) || ($network == Protocol::DIASPORA)) { $result = self::diaspora($webfinger); + } else { + $result['networks'][Protocol::DIASPORA] = self::diaspora($webfinger); } if ((!$result && ($network == '')) || ($network == Protocol::OSTATUS)) { $result = self::ostatus($webfinger); + } else { + $result['networks'][Protocol::OSTATUS] = self::ostatus($webfinger); } if (in_array($network, ['', Protocol::ZOT])) { $result = self::zot($webfinger, $result, $baseurl); diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 3c60f4041..e5194ba3d 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -826,9 +826,15 @@ class Diaspora */ public static function isSupportedByContactUrl(string $url, ?bool $update = null): bool { - $contact = Contact::getByURL($url, $update); + $contact = Contact::getByURL($url, $update, ['uri-id', 'network']); - return DI::dsprContact()->existsByUriId($contact['uri-id'] ?? 0); + $supported = DI::dsprContact()->existsByUriId($contact['uri-id'] ?? 0); + + if (!$supported && is_null($update) && ($contact['network'] == Protocol::DFRN)) { + $supported = self::isSupportedByContactUrl($url, true); + } + + return $supported; } /** @@ -4035,6 +4041,7 @@ class Diaspora if (!self::parentSupportDiaspora($item['thr-parent-id'])) { Logger::info('One of the parents does not support Diaspora. A signature will not be created.', ['uri-id' => $item['uri-id'], 'guid' => $item['guid']]); + echo "5"; return false; } @@ -4064,7 +4071,7 @@ class Diaspora return false; } - if (!self::isSupportedByContactUrl($parent_post['author-link'], false)) { + if (!self::isSupportedByContactUrl($parent_post['author-link'])) { Logger::info('Parent author is no Diaspora contact.', ['parent-id' => $parent_id]); return false; } diff --git a/src/Worker/Delivery.php b/src/Worker/Delivery.php index cec894480..1a0758987 100644 --- a/src/Worker/Delivery.php +++ b/src/Worker/Delivery.php @@ -277,7 +277,7 @@ class Delivery private static function deliverDFRN(string $cmd, array $contact, array $owner, array $items, array $target_item, bool $public_message, bool $top_level, bool $followup, int $server_protocol = null) { // Transmit Diaspora reshares via Diaspora if the Friendica contact support Diaspora - if (Diaspora::getReshareDetails($target_item ?? []) && Diaspora::isSupportedByContactUrl($contact['addr'], false)) { + if (Diaspora::getReshareDetails($target_item ?? []) && Diaspora::isSupportedByContactUrl($contact['addr'])) { Logger::info('Reshare will be transmitted via Diaspora', ['url' => $contact['url'], 'guid' => ($target_item['guid'] ?? '') ?: $target_item['id']]); self::deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup); return; diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index db593b6a4..c09faca89 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -191,7 +191,7 @@ class Notifier // when the original comment author does support the Diaspora protocol. if ($thr_parent['author-link'] && $target_item['parent-uri'] != $target_item['thr-parent']) { $diaspora_delivery = Diaspora::isSupportedByContactUrl($thr_parent['author-link']); - if ($diaspora_delivery && empty($target_item['signed_text'])) { + if ($diaspora_delivery && empty($target_item['signed_text'])) { Logger::debug('Post has got no Diaspora signature, so there will be no Diaspora delivery', ['guid' => $target_item['guid'], 'uri-id' => $target_item['uri-id']]); $diaspora_delivery = false; } From 6496ed4c1910c39394eec8066dc7a2f958a16a1b Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 10 Dec 2022 12:14:23 +0000 Subject: [PATCH 03/21] Remove testcode, improve rearrange --- src/Network/Probe.php | 6 +++--- src/Protocol/Diaspora.php | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Network/Probe.php b/src/Network/Probe.php index 9cdcd5fa8..a97f6f811 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -134,10 +134,10 @@ class Probe } } - $newdata['networks'] = $data['networks'] ?? []; + $newdata['networks'] = []; foreach ([Protocol::DIASPORA, Protocol::OSTATUS] as $network) { - if (empty($newdata['networks'][$network])) { - unset($newdata['networks'][$network]); + if (!empty($data['networks'][$network])) { + $newdata['networks'][$network] = $data['networks'][$network]; } } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index e5194ba3d..fe5b27d33 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -4041,7 +4041,6 @@ class Diaspora if (!self::parentSupportDiaspora($item['thr-parent-id'])) { Logger::info('One of the parents does not support Diaspora. A signature will not be created.', ['uri-id' => $item['uri-id'], 'guid' => $item['guid']]); - echo "5"; return false; } From c6ca844f33cba1c4cf5bdfd2127f0fa751ea25b4 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 10 Dec 2022 12:35:05 +0000 Subject: [PATCH 04/21] "networks" has to contain all probing fields --- src/Network/Probe.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Network/Probe.php b/src/Network/Probe.php index a97f6f811..e74b43734 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -137,7 +137,11 @@ class Probe $newdata['networks'] = []; foreach ([Protocol::DIASPORA, Protocol::OSTATUS] as $network) { if (!empty($data['networks'][$network])) { - $newdata['networks'][$network] = $data['networks'][$network]; + $data['networks'][$network]['subscribe'] = $newdata['subscribe'] ?? ''; + $data['networks'][$network]['baseurl'] = $newdata['baseurl'] ?? ''; + $data['networks'][$network]['gsid'] = $newdata['gsid'] ?? 0; + $newdata['networks'][$network] = self::rearrangeData($data['networks'][$network]); + unset($newdata['networks'][$network]['networks']); } } From 19d11c08d4017b912367289f96e84ba6e868b1c5 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 10 Dec 2022 09:23:29 -0500 Subject: [PATCH 05/21] Change DiasporaContact->subscribe type to string - This avoids the expected "{uri}" placeholder to be URL-encoded in the string representation --- src/Protocol/Diaspora/Entity/DiasporaContact.php | 4 ++-- src/Protocol/Diaspora/Factory/DiasporaContact.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Protocol/Diaspora/Entity/DiasporaContact.php b/src/Protocol/Diaspora/Entity/DiasporaContact.php index 7fbd2831f..a5ad1f08a 100644 --- a/src/Protocol/Diaspora/Entity/DiasporaContact.php +++ b/src/Protocol/Diaspora/Entity/DiasporaContact.php @@ -82,7 +82,7 @@ class DiasporaContact extends \Friendica\BaseEntity protected $notify; /** @var UriInterface */ protected $poll; - /** @var UriInterface */ + /** @var string URL pattern string including a placeholder "{uri}" that mustn't be URL-encoded */ protected $subscribe; /** @var bool */ protected $searchable; @@ -107,7 +107,7 @@ class DiasporaContact extends \Friendica\BaseEntity UriInterface $url, \DateTime $created, string $guid = null, string $addr = null, UriInterface $alias = null, string $nick = null, string $name = null, string $givenName = null, string $familyName = null, UriInterface $photo = null, UriInterface $photoMedium = null, UriInterface $photoSmall = null, - UriInterface $batch = null, UriInterface $notify = null, UriInterface $poll = null, UriInterface $subscribe = null, + UriInterface $batch = null, UriInterface $notify = null, UriInterface $poll = null, string $subscribe = null, bool $searchable = null, string $pubKey = null, UriInterface $baseurl = null, int $gsid = null, \DateTime $updated = null, int $interacting_count = 0, int $interacted_count = 0, int $post_count = 0, int $uriId = null ) { diff --git a/src/Protocol/Diaspora/Factory/DiasporaContact.php b/src/Protocol/Diaspora/Factory/DiasporaContact.php index d5c91d200..0389b81ee 100644 --- a/src/Protocol/Diaspora/Factory/DiasporaContact.php +++ b/src/Protocol/Diaspora/Factory/DiasporaContact.php @@ -45,7 +45,7 @@ class DiasporaContact extends \Friendica\BaseFactory implements ICanCreateFromTa $row['batch'] ? new Uri($row['batch']) : null, $row['notify'] ? new Uri($row['notify']) : null, $row['poll'] ? new Uri($row['poll']) : null, - $row['subscribe'] ? new Uri($row['subscribe']) : null, + $row['subscribe'], $row['searchable'], $row['pubkey'], $row['baseurl'] ? new Uri($row['baseurl']) : null, @@ -87,7 +87,7 @@ class DiasporaContact extends \Friendica\BaseFactory implements ICanCreateFromTa $data['batch'] ? new Uri($data['batch']) : null, $data['notify'] ? new Uri($data['notify']) : null, $data['poll'] ? new Uri($data['poll']) : null, - $data['subscribe'] ? new Uri($data['subscribe']) : null, + $data['subscribe'], !$data['hide'], $data['pubkey'], $data['baseurl'] ? new Uri($data['baseurl']) : null, From ab1ff53b18f24a532c89c295940ed500853507d5 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 10 Dec 2022 15:59:11 +0000 Subject: [PATCH 06/21] Diaspora added to localprobe --- src/Network/Probe.php | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Network/Probe.php b/src/Network/Probe.php index e74b43734..8a8e1a01f 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -38,6 +38,7 @@ use Friendica\Network\HTTPClient\Client\HttpClientAccept; use Friendica\Network\HTTPClient\Client\HttpClientOptions; use Friendica\Protocol\ActivityNamespace; use Friendica\Protocol\ActivityPub; +use Friendica\Protocol\Diaspora; use Friendica\Protocol\Email; use Friendica\Protocol\Feed; use Friendica\Protocol\Salmon; @@ -358,7 +359,9 @@ class Probe if (empty($data) || (!empty($ap_profile) && empty($network) && (($data['network'] ?? '') != Protocol::DFRN))) { $networks = $data['networks'] ?? []; unset($data['networks']); - $networks[$data['network']] = $data; + if (!empty($data['network'])) { + $networks[$data['network']] = $data; + } $data = $ap_profile; $data['networks'] = $networks; } elseif (!empty($ap_profile)) { @@ -2207,6 +2210,10 @@ class Probe $owner = User::getOwnerDataById($uid); $approfile = ActivityPub\Transmitter::getProfile($uid); + $split_name = Diaspora::splitName($owner['name']); + $firstname = $split_name['first']; + $lastname = $split_name['last']; + if (empty($owner['gsid'])) { $owner['gsid'] = GServer::getID($approfile['generator']['url']); } @@ -2226,7 +2233,28 @@ class Probe 'inbox' => $approfile['inbox'], 'outbox' => $approfile['outbox'], 'sharedinbox' => $approfile['endpoints']['sharedInbox'], 'network' => Protocol::DFRN, 'pubkey' => $owner['upubkey'], 'baseurl' => $approfile['generator']['url'], 'gsid' => $owner['gsid'], - 'manually-approve' => in_array($owner['page-flags'], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP]) + 'manually-approve' => in_array($owner['page-flags'], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP]), + 'networks' => [ + Protocol::DIASPORA => [ + 'name' => $owner['name'], + 'given_name' => $firstname, + 'family_name' => $lastname, + 'nick' => $owner['nick'], + 'guid' => $approfile['diaspora:guid'], + 'url' => $owner['url'], + 'addr' => $owner['addr'], + 'alias' => $owner['alias'], + 'photo' => $owner['photo'], + 'photo_medium' => $owner['thumb'], + 'photo_small' => $owner['micro'], + 'batch' => $approfile['generator']['url'] . '/receive/public', + 'notify' => $owner['notify'], + 'poll' => $owner['poll'], + 'poco' => $owner['poco'], + 'network' => Protocol::DIASPORA, + 'pubkey' => $owner['upubkey'], + ] + ] ]; } catch (Exception $e) { // Default values for non existing targets From 2761972742da079d58b91d7f125cc1dd33c6db3e Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 10 Dec 2022 16:02:38 +0000 Subject: [PATCH 07/21] Simplify lastname/firstname --- src/Network/Probe.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Network/Probe.php b/src/Network/Probe.php index 8a8e1a01f..5beef2ea8 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -2211,8 +2211,6 @@ class Probe $approfile = ActivityPub\Transmitter::getProfile($uid); $split_name = Diaspora::splitName($owner['name']); - $firstname = $split_name['first']; - $lastname = $split_name['last']; if (empty($owner['gsid'])) { $owner['gsid'] = GServer::getID($approfile['generator']['url']); @@ -2237,8 +2235,8 @@ class Probe 'networks' => [ Protocol::DIASPORA => [ 'name' => $owner['name'], - 'given_name' => $firstname, - 'family_name' => $lastname, + 'given_name' => $split_name['first'], + 'family_name' => $split_name['last'], 'nick' => $owner['nick'], 'guid' => $approfile['diaspora:guid'], 'url' => $owner['url'], From e7574356d83ec698afcc942103c0aa1c14000860 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 7 Dec 2022 22:08:48 -0500 Subject: [PATCH 08/21] Replace parse_url with UriInterface instantiation in Model\APContact - Address part of https://github.com/friendica/friendica/issues/12011#issuecomment-1338133783 --- src/Model/APContact.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Model/APContact.php b/src/Model/APContact.php index 67ce2b66b..fd748f1cd 100644 --- a/src/Model/APContact.php +++ b/src/Model/APContact.php @@ -291,14 +291,11 @@ class APContact return $fetched_contact; } - $parts = parse_url($apcontact['url']); - unset($parts['scheme']); - unset($parts['path']); - if (empty($apcontact['addr'])) { - if (!empty($apcontact['nick']) && is_array($parts)) { - $apcontact['addr'] = $apcontact['nick'] . '@' . str_replace('//', '', Network::unparseURL($parts)); - } else { + try { + $apcontact['addr'] = $apcontact['nick'] . '@' . (new Uri($apcontact['url']))->getAuthority(); + } catch (\Throwable $e) { + Logger::warning('Unable to coerce APContact URL into a UriInterface object', ['url' => $apcontact['url'], 'error' => $e->getMessage()]); $apcontact['addr'] = ''; } } From 1622ce0a998b99683df6ca0d6e2f36393a179739 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 7 Dec 2022 22:10:38 -0500 Subject: [PATCH 09/21] Coalesce null activity name in ActivityPub\Processor - Address part of https://github.com/friendica/friendica/issues/12011#issuecomment-1338133783 --- src/Protocol/ActivityPub/Processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 8e21a6644..60a5c8d74 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -804,7 +804,7 @@ class Processor private static function processContent(array $activity, array $item) { if (!empty($activity['mediatype']) && ($activity['mediatype'] == 'text/markdown')) { - $item['title'] = strip_tags($activity['name']); + $item['title'] = strip_tags($activity['name'] ?? ''); $content = Markdown::toBBCode($activity['content']); } elseif (!empty($activity['mediatype']) && ($activity['mediatype'] == 'text/bbcode')) { $item['title'] = $activity['name']; From 0af2be14eec590ca55bec12b6e37beed588d0436 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 7 Dec 2022 22:15:47 -0500 Subject: [PATCH 10/21] Check for parts key existence before performing strpos in Network\Probe - Address part of https://github.com/friendica/friendica/issues/12011#issuecomment-1338133783 --- src/Network/Probe.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Network/Probe.php b/src/Network/Probe.php index e74b43734..87c28619d 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -684,7 +684,7 @@ class Probe } $parts = parse_url($uri); - if (empty($parts['scheme']) && empty($parts['host']) && !strstr($parts['path'], '@')) { + if (empty($parts['scheme']) && empty($parts['host']) && (empty($parts['path']) || strpos($parts['path'], '@') === false)) { Logger::info('URI was not detectable', ['uri' => $uri]); return []; } From fc246424a907e91fc19a4aa9ac7ef3526523607e Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 7 Dec 2022 22:21:23 -0500 Subject: [PATCH 11/21] Provide default host value to hash() in Model\Item::guidFromUri - Address part of https://github.com/friendica/friendica/issues/12011#issuecomment-1338133783 --- src/Contact/Avatar.php | 2 +- src/Model/Contact.php | 4 ++-- src/Model/Item.php | 10 ++++++++-- src/Model/Mail.php | 3 +-- src/Protocol/Feed.php | 4 ++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Contact/Avatar.php b/src/Contact/Avatar.php index 0cfc8df34..711a8549f 100644 --- a/src/Contact/Avatar.php +++ b/src/Contact/Avatar.php @@ -125,7 +125,7 @@ class Avatar private static function getFilename(string $url): string { - $guid = Item::guidFromUri($url, parse_url($url, PHP_URL_HOST)); + $guid = Item::guidFromUri($url); return substr($guid, 0, 2) . '/' . substr($guid, 3, 2) . '/' . substr($guid, 5, 3) . '/' . substr($guid, 9, 2) .'/' . substr($guid, 11, 2) . '/' . substr($guid, 13, 4). '/' . substr($guid, 18) . '-'; diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 873de0890..4a10fd98e 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -2099,7 +2099,7 @@ class Contact if ($static) { $query_params['static'] = true; } - + return $url . ($guid ?: $cid) . (!empty($query_params) ? '?' . http_build_query($query_params) : ''); } @@ -2675,7 +2675,7 @@ class Contact } $update = false; - $guid = ($ret['guid'] ?? '') ?: Item::guidFromUri($ret['url'], parse_url($ret['url'], PHP_URL_HOST)); + $guid = ($ret['guid'] ?? '') ?: Item::guidFromUri($ret['url']); // make sure to not overwrite existing values with blank entries except some technical fields $keep = ['batch', 'notify', 'poll', 'request', 'confirm', 'poco', 'baseurl']; diff --git a/src/Model/Item.php b/src/Model/Item.php index ff4791a7c..8b9909f8b 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -2034,9 +2034,10 @@ class Item * Posts that are created on this system are using System::createUUID. * Received ActivityPub posts are using Processor::getGUIDByURL. * - * @param string $uri uri of an item entry + * @param string $uri uri of an item entry * @param string|null $host hostname for the GUID prefix * @return string Unique guid + * @throws \Exception */ public static function guidFromUri(string $uri, string $host = null): string { @@ -2047,11 +2048,16 @@ class Item // Remove the scheme to make sure that "https" and "http" doesn't make a difference unset($parsed['scheme']); + $hostPart = $host ?? $parsed['host'] ?? ''; + if (!$hostPart) { + Logger::warning('Empty host GUID part', ['uri' => $uri, 'host' => $host, 'parsed' => $parsed, 'callstack' => System::callstack(10)]); + } + // Glue it together to be able to make a hash from it $host_id = implode('/', $parsed); // Use a mixture of several hashes to provide some GUID like experience - return hash('crc32', $host) . '-'. hash('joaat', $host_id) . '-'. hash('fnv164', $host_id); + return hash('crc32', $hostPart) . '-' . hash('joaat', $host_id) . '-' . hash('fnv164', $host_id); } /** diff --git a/src/Model/Mail.php b/src/Model/Mail.php index 6ccce24ba..9469483d9 100644 --- a/src/Model/Mail.php +++ b/src/Model/Mail.php @@ -59,8 +59,7 @@ class Mail } if (empty($msg['guid'])) { - $host = parse_url($msg['from-url'], PHP_URL_HOST); - $msg['guid'] = Item::guidFromUri($msg['uri'], $host); + $msg['guid'] = Item::guidFromUri($msg['uri'], parse_url($msg['from-url'], PHP_URL_HOST)); } $msg['created'] = (!empty($msg['created']) ? DateTimeFormat::utc($msg['created']) : DateTimeFormat::utcNow()); diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index 29b192331..dec463820 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -625,8 +625,8 @@ class Feed $notify = Item::isRemoteSelf($contact, $item); - // Distributed items should have a well formatted URI. - // Additionally we have to avoid conflicts with identical URI between imported feeds and these items. + // Distributed items should have a well-formatted URI. + // Additionally, we have to avoid conflicts with identical URI between imported feeds and these items. if ($notify) { $item['guid'] = Item::guidFromUri($orig_plink, DI::baseUrl()->getHostname()); $item['uri'] = Item::newURI($item['guid']); From f3dc69c226ea15f5ea5b1f1b470ee74c27313ef7 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 7 Dec 2022 22:24:01 -0500 Subject: [PATCH 12/21] Ensure strpos is provided a string in App::runFrontend - Address part of https://github.com/friendica/friendica/issues/12011#issuecomment-1338133783 --- src/App.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App.php b/src/App.php index 25770dd78..0d4e8880d 100644 --- a/src/App.php +++ b/src/App.php @@ -631,10 +631,10 @@ class App // ZRL if (!empty($_GET['zrl']) && $this->mode->isNormal() && !$this->mode->isBackend() && !$this->session->getLocalUserId()) { - // Only continue when the given profile link seems valid + // Only continue when the given profile link seems valid. // Valid profile links contain a path with "/profile/" and no query parameters if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == '') && - strstr(parse_url($_GET['zrl'], PHP_URL_PATH), '/profile/')) { + strpos(parse_url($_GET['zrl'], PHP_URL_PATH) ?? '', '/profile/') !== false) { if ($this->session->get('visitor_home') != $_GET['zrl']) { $this->session->set('my_url', $_GET['zrl']); $this->session->set('authenticated', 0); From c70d657885351a780b222c784681104f7f1dc8c6 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 7 Dec 2022 22:28:09 -0500 Subject: [PATCH 13/21] Ward against invalid name from receiver in ActivityPub::storeReceivers - Address part of https://github.com/friendica/friendica/issues/12011#issuecomment-1338133783 --- src/Protocol/ActivityPub/Processor.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 60a5c8d74..d098ddb69 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -1273,8 +1273,11 @@ class Processor foreach ($receivers[$element] as $receiver) { if ($receiver == ActivityPub::PUBLIC_COLLECTION) { $name = Receiver::PUBLIC_COLLECTION; + } elseif ($path = parse_url($receiver, PHP_URL_PATH)) { + $name = trim($path, '/'); } else { - $name = trim(parse_url($receiver, PHP_URL_PATH), '/'); + Logger::warning('Unable to coerce name from receiver', ['receiver' => $receiver]); + $name = ''; } $target = Tag::getTargetType($receiver); From b1860d412119ba6a3e4d3e5389651017f741e09a Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 7 Dec 2022 22:31:27 -0500 Subject: [PATCH 14/21] Check for last-activity value before feeding it to strtotime in Module\NoScrape - Address https://github.com/friendica/friendica/issues/12011#issuecomment-1340019523 --- src/Module/NoScrape.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/NoScrape.php b/src/Module/NoScrape.php index 8e5850ac0..56f31f2dc 100644 --- a/src/Module/NoScrape.php +++ b/src/Module/NoScrape.php @@ -94,7 +94,7 @@ class NoScrape extends BaseModule // We display the last activity (post or login), reduced to year and week number $last_active = strtotime($owner['last-item']); - if ($last_active < strtotime($owner['last-activity'])) { + if ($owner['last-activity'] && $last_active < strtotime($owner['last-activity'])) { $last_active = strtotime($owner['last-activity']); } $json_info['last-activity'] = date('o-W', $last_active); From 607d26e90676a8ab9a6a824aba9918753a61109d Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 7 Dec 2022 22:35:37 -0500 Subject: [PATCH 15/21] Ward against empty JsonLD::fetchElement result in ActivityPub\Receiver::processTags - Address https://github.com/friendica/friendica/issues/12011#issuecomment-1336478368 --- src/Protocol/ActivityPub/Receiver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 4e2bcceaf..893982274 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -209,7 +209,7 @@ class Receiver Logger::notice('No object data found', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor, 'activity' => $activity]); return; } - + if (self::routeActivities($object_data, $type, true)) { Logger::debug('Handled activity', ['type' => $type, 'object_type' => $object_type, 'object_id' => $object_id, 'actor' => $actor]); } else { @@ -1472,7 +1472,7 @@ class Receiver continue; } - $element = ['type' => str_replace('as:', '', JsonLD::fetchElement($tag, '@type')), + $element = ['type' => str_replace('as:', '', JsonLD::fetchElement($tag, '@type') ?? ''), 'href' => JsonLD::fetchElement($tag, 'as:href', '@id'), 'name' => JsonLD::fetchElement($tag, 'as:name', '@value')]; From 7aa5407bbdc86a375d9c14f1ea7d3d82e9f8ea07 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 8 Dec 2022 08:51:49 -0500 Subject: [PATCH 16/21] Remove superfluous strlen call in Module\Tos - Address https://github.com/friendica/friendica/issues/12011#issuecomment-1342617099 --- src/Module/Tos.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/Tos.php b/src/Module/Tos.php index 822aa8813..11cecac44 100644 --- a/src/Module/Tos.php +++ b/src/Module/Tos.php @@ -77,7 +77,7 @@ class Tos extends BaseModule */ protected function content(array $request = []): string { - if (strlen($this->config->get('system', 'singleuser'))) { + if ($this->config->get('system', 'singleuser')) { $this->baseUrl->redirect('profile/' . $this->config->get('system', 'singleuser')); } From d87585477cb5c68d24442fb329581f88c1dfe8e9 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 8 Dec 2022 09:24:06 -0500 Subject: [PATCH 17/21] Delete introductions when referenced contact id doesn't exist anymore in Ping module - Address part of https://github.com/friendica/friendica/issues/11993#issuecomment-1338134893 --- src/Module/Notifications/Ping.php | 9 +++++-- .../Factory/FormattedNavNotification.php | 24 +++++++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/Module/Notifications/Ping.php b/src/Module/Notifications/Ping.php index 76cdd9f77..df75c047a 100644 --- a/src/Module/Notifications/Ping.php +++ b/src/Module/Notifications/Ping.php @@ -48,6 +48,7 @@ use Friendica\Navigation\Notifications\Factory; use Friendica\Navigation\Notifications\Repository; use Friendica\Navigation\Notifications\ValueObject; use Friendica\Navigation\SystemMessages; +use Friendica\Network\HTTPException; use Friendica\Protocol\Activity; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; @@ -229,7 +230,11 @@ class Ping extends BaseModule // merge all notification types in one array foreach ($intros as $intro) { - $navNotifications[] = $this->formattedNavNotification->createFromIntro($intro); + try { + $navNotifications[] = $this->formattedNavNotification->createFromIntro($intro); + } catch (HTTPException\NotFoundException $e) { + $this->introductionRepo->delete($intro); + } } if (count($registrations) <= 1 || $this->pconfig->get($this->session->getLocalUserId(), 'system', 'detailed_notif')) { @@ -242,7 +247,7 @@ class Ping extends BaseModule new Uri($this->baseUrl->get(true) . '/moderation/users/pending') ); } - } elseif (count($registrations) > 1) { + } else { $navNotifications[] = $this->formattedNavNotification->createFromParams( $registrations[0]['name'], $registrations[0]['url'], diff --git a/src/Navigation/Notifications/Factory/FormattedNavNotification.php b/src/Navigation/Notifications/Factory/FormattedNavNotification.php index 2b1360eaa..9813fbf85 100644 --- a/src/Navigation/Notifications/Factory/FormattedNavNotification.php +++ b/src/Navigation/Notifications/Factory/FormattedNavNotification.php @@ -28,7 +28,7 @@ use Friendica\Model\Contact; use Friendica\Navigation\Notifications\Entity; use Friendica\Navigation\Notifications\Exception\NoMessageException; use Friendica\Navigation\Notifications\ValueObject; -use Friendica\Network\HTTPException\ServiceUnavailableException; +use Friendica\Network\HTTPException; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy; use Friendica\Util\Temporal; @@ -73,7 +73,7 @@ class FormattedNavNotification extends BaseFactory * @param Uri $href * @param bool $seen * @return ValueObject\FormattedNavNotification - * @throws ServiceUnavailableException + * @throws HTTPException\ServiceUnavailableException */ public function createFromParams(string $contact_name, string $contact_url, string $message, \DateTime $date, Uri $href, bool $seen = false): ValueObject\FormattedNavNotification { @@ -115,9 +115,9 @@ class FormattedNavNotification extends BaseFactory * @param Entity\Notification $notification * @return ValueObject\FormattedNavNotification * @throws NoMessageException - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - * @throws \Friendica\Network\HTTPException\NotFoundException - * @throws \Friendica\Network\HTTPException\ServiceUnavailableException + * @throws HTTPException\InternalServerErrorException + * @throws HTTPException\NotFoundException + * @throws HTTPException\ServiceUnavailableException */ public function createFromNotification(Entity\Notification $notification): ValueObject\FormattedNavNotification { @@ -141,10 +141,20 @@ class FormattedNavNotification extends BaseFactory ); } + /** + * @param \Friendica\Contact\Introduction\Entity\Introduction $intro + * @return ValueObject\FormattedNavNotification + * @throws HTTPException\NotFoundException when the contact record couldn't be located + * @throws HTTPException\ServiceUnavailableException + */ public function createFromIntro(\Friendica\Contact\Introduction\Entity\Introduction $intro): ValueObject\FormattedNavNotification { - if (!isset(self::$contacts[$intro->cid])) { - self::$contacts[$intro->cid] = Contact::getById($intro->cid, ['name', 'url', 'pending']); + if (empty(self::$contacts[$intro->cid])) { + if ($contact = Contact::getById($intro->cid, ['name', 'url', 'pending'])) { + self::$contacts[$intro->cid] = $contact; + } else { + throw new HTTPException\NotFoundException('Contact not found with id' . $intro->cid); + } } if (self::$contacts[$intro->cid]['pending']) { From e78471c847a1c590439012639a9200aea1c622c6 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 8 Dec 2022 09:40:35 -0500 Subject: [PATCH 18/21] Throw exception when a few keys are missing from probe data array in Repository\DiasporaContact - Address part of https://github.com/friendica/friendica/issues/11993#issuecomment-1338134893 --- src/Model/Contact.php | 32 ++++++++++++++----- .../Diaspora/Repository/DiasporaContact.php | 12 +++++++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 873de0890..79ddae713 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1395,9 +1395,17 @@ class Contact } if ($data['network'] == Protocol::DIASPORA) { - DI::dsprContact()->updateFromProbeArray($data); + try { + DI::dsprContact()->updateFromProbeArray($data); + } catch (\InvalidArgumentException $e) { + Logger::error($e->getMessage(), ['url' => $url, 'data' => $data]); + } } elseif (!empty($data['networks'][Protocol::DIASPORA])) { - DI::dsprContact()->updateFromProbeArray($data['networks'][Protocol::DIASPORA]); + try { + DI::dsprContact()->updateFromProbeArray($data['networks'][Protocol::DIASPORA]); + } catch (\InvalidArgumentException $e) { + Logger::error($e->getMessage(), ['url' => $url, 'data' => $data['networks'][Protocol::DIASPORA]]); + } } self::updateFromProbeArray($contact_id, $data); @@ -2485,15 +2493,23 @@ class Contact return false; } - $ret = Probe::uri($contact['url'], $network, $contact['uid']); + $data = Probe::uri($contact['url'], $network, $contact['uid']); - if ($ret['network'] == Protocol::DIASPORA) { - DI::dsprContact()->updateFromProbeArray($ret); - } elseif (!empty($ret['networks'][Protocol::DIASPORA])) { - DI::dsprContact()->updateFromProbeArray($ret['networks'][Protocol::DIASPORA]); + if ($data['network'] == Protocol::DIASPORA) { + try { + DI::dsprContact()->updateFromProbeArray($data); + } catch (\InvalidArgumentException $e) { + Logger::error($e->getMessage(), ['id' => $id, 'network' => $network, 'contact' => $contact, 'data' => $data]); + } + } elseif (!empty($data['networks'][Protocol::DIASPORA])) { + try { + DI::dsprContact()->updateFromProbeArray($data['networks'][Protocol::DIASPORA]); + } catch (\InvalidArgumentException $e) { + Logger::error($e->getMessage(), ['id' => $id, 'network' => $network, 'contact' => $contact, 'data' => $data]); + } } - return self::updateFromProbeArray($id, $ret); + return self::updateFromProbeArray($id, $data); } /** diff --git a/src/Protocol/Diaspora/Repository/DiasporaContact.php b/src/Protocol/Diaspora/Repository/DiasporaContact.php index ac8d200aa..1669707b9 100644 --- a/src/Protocol/Diaspora/Repository/DiasporaContact.php +++ b/src/Protocol/Diaspora/Repository/DiasporaContact.php @@ -234,6 +234,18 @@ class DiasporaContact extends BaseRepository */ public function updateFromProbeArray(array $data): Entity\DiasporaContact { + if (empty($data['url'])) { + throw new \InvalidArgumentException('Missing url key in Diaspora probe data array'); + } + + if (empty($data['guid'])) { + throw new \InvalidArgumentException('Missing guid key in Diaspora probe data array'); + } + + if (empty($data['pubkey'])) { + throw new \InvalidArgumentException('Missing pubkey key in Diaspora probe data array'); + } + $uriId = ItemURI::insert(['uri' => $data['url'], 'guid' => $data['guid']]); $contact = Contact::getByUriId($uriId, ['id', 'created']); From a71fb8d7f3a8cab8dd16be142ce271256ecf99cc Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 8 Dec 2022 09:41:08 -0500 Subject: [PATCH 19/21] Check for existence of a public contact id before deleting related notifications in Model\Contact - Address part of https://github.com/friendica/friendica/issues/11993#issuecomment-1338134893 --- src/Model/Contact.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 79ddae713..d3ff4a2ef 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -3209,8 +3209,9 @@ class Contact self::clearFollowerFollowingEndpointCache($contact['uid']); $cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']); - - DI::notification()->deleteForUserByVerb($contact['uid'], Activity::FOLLOW, ['actor-id' => $cdata['public']]); + if (!empty($cdata['public'])) { + DI::notification()->deleteForUserByVerb($contact['uid'], Activity::FOLLOW, ['actor-id' => $cdata['public']]); + } } /** From 71a7f2d5034211a3e640c24663e0bad7a24c466a Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 8 Dec 2022 09:45:33 -0500 Subject: [PATCH 20/21] Remove parameter-less call of OStatus\Salmon module in DFRN\Notify - Address https://github.com/friendica/friendica/issues/11993#issuecomment-1342615279 --- src/Module/DFRN/Notify.php | 14 ++------------ src/Module/OStatus/Salmon.php | 9 +++++---- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/Module/DFRN/Notify.php b/src/Module/DFRN/Notify.php index 34cf21f11..14b121e81 100644 --- a/src/Module/DFRN/Notify.php +++ b/src/Module/DFRN/Notify.php @@ -70,18 +70,8 @@ class Notify extends BaseModule throw new \Friendica\Network\HTTPException\InternalServerErrorException(); } $this->dispatchPrivate($user, $postdata); - } elseif (!$this->dispatchPublic($postdata)) { - (new Salmon( - $this->database, - $this->l10n, - $this->baseUrl, - $this->args, - $this->logger, - $this->profiler, - $this->response, - $this->server, - $this->parameters - ))->rawContent($request); + } else { + $this->dispatchPublic($postdata); } } diff --git a/src/Module/OStatus/Salmon.php b/src/Module/OStatus/Salmon.php index 0d393afcc..f928e308d 100644 --- a/src/Module/OStatus/Salmon.php +++ b/src/Module/OStatus/Salmon.php @@ -66,11 +66,12 @@ class Salmon extends \Friendica\BaseModule { $xml = Network::postdata(); - $this->logger->debug('New Salmon', ['nickname' => $this->parameters['nickname'], 'xml' => $xml]); - - // Despite having a route with a mandatory nickname parameter, this method can also be called from - // \Friendica\Module\DFRN\Notify->post where the same parameter is optional 🤷‍ $nickname = $this->parameters['nickname'] ?? ''; + if (empty($nickname)) { + throw new HTTPException\BadRequestException('nickname parameter is mandatory'); + } + + $this->logger->debug('New Salmon', ['nickname' => $nickname, 'xml' => $xml]); $importer = $this->database->selectFirst('user', [], ['nickname' => $nickname, 'account_expired' => false, 'account_removed' => false]); if (!$this->database->isResult($importer)) { From 870fd1a52bffb79861a3c8298f4c0e91c92428f2 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 10 Dec 2022 19:08:56 +0000 Subject: [PATCH 21/21] ID added for list of images in a post --- src/Content/Text/BBCode.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index ae21d05e1..62ad04a43 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -273,8 +273,8 @@ class BBCode // Get all linked images with alternative image description if (preg_match_all("/\[img=(http[^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { foreach ($pictures as $picture) { - if (Photo::isLocal($picture[1])) { - $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => $picture[2]]; + if ($id = Photo::getIdForName($picture[1])) { + $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => $picture[2], 'id' => $id]; } else { $post['remote_images'][] = ['url' => $picture[1], 'description' => $picture[2]]; } @@ -286,8 +286,8 @@ class BBCode if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { foreach ($pictures as $picture) { - if (Photo::isLocal($picture[1])) { - $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => '']; + if ($id = Photo::getIdForName($picture[1])) { + $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => '', 'id' => $id]; } else { $post['remote_images'][] = ['url' => $picture[1], 'description' => '']; }