From e001c86b4a41f9e950a899b8215b1d69fb7841ed Mon Sep 17 00:00:00 2001 From: Mike Macgirvin Date: Sun, 16 Jun 2024 08:55:21 +1000 Subject: [PATCH] rework delivery permissions to allow sender, owner, and mentions --- include/items.php | 2 +- include/permissions.php | 60 ++++++++++++++++++++++++++++++++--------- src/Daemon/Notifier.php | 6 ++--- 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/include/items.php b/include/items.php index b7f796390..b1690c9eb 100644 --- a/include/items.php +++ b/include/items.php @@ -125,7 +125,7 @@ function collect_recipients($item, &$private_envelope) { // This is a somewhat expensive operation but important. // Don't send this item to anybody who doesn't have the deliver_stream permission - $recipients = check_deliver_permissions($item['uid'],$recipients); + $recipients = check_deliver_permissions($item,$recipients); // Add both the author and owner (if different). diff --git a/include/permissions.php b/include/permissions.php index 548df0627..abaeb998e 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -515,9 +515,11 @@ function check_list_permissions($uid, $arr, $perm) return($result); } -function check_deliver_permissions($uid, $arr) +function check_deliver_permissions($item, $arr) { $result = []; + $uid = $item['uid'] ?? 0; + $terms = ((isset($item['term'])) ? get_terms_oftype($item['term'], [TERM_MENTION, TERM_GROUP]) : false); // Find actors we are not delivering to. $r = q("select * from abconfig where chan = %d and cat = 'system' and k = 'my_perms' and v not like '%%deliver_stream%%'", intval($uid) @@ -533,27 +535,59 @@ function check_deliver_permissions($uid, $arr) // Filter the recipient list accordingly. if ($arr) { - foreach ($arr as $x) { + foreach ($arr as $recipient) { $accepting = $deliverable = false; - if (in_array($x, $theyAccept)) { + if (in_array($recipient, $theyAccept)) { $accepting = true; } - if (!in_array($x,$willNotSend)) { + if (!in_array($recipient,$willNotSend)) { $deliverable = true; } - if ($deliverable && !$accepting) { + if (in_array($recipient, [$item['author_xchan'], $item['owner_xchan']])) { + $deliverable = $accepting = true; + } + if (!$deliverable || !$accepting) { // Groups don't generally provide send_stream permission as they aren't really following you, // but they do allow you to send them group targeted posts. - $r = q("select xchan_hash from xchan where xchan_hash = '%s' and xchan_type = %d ", - dbesc($x), - intval(XCHAN_TYPE_GROUP) - ); - if ($r) { - $result[] = $x; + if ($deliverable) { + $r = q("select xchan_hash from xchan where xchan_hash = '%s' and xchan_type = %d", + dbesc($recipient), + intval(XCHAN_TYPE_GROUP) + ); + if ($r) { + if ($r && !in_array($recipient, $result)) { + $result[] = $recipient; + continue; + } + } + } + // Send mentions even if you have no permission to do so. They might allow it. + if ($terms) { + foreach ($terms as $term) { + if (in_array($term['url'], $result)) { + continue; + } + // activitypub is easy because $x will match directly on the mention url + if ($recipient === $term['url'] && (!in_array($recipient, $result))) { + $result[] = $recipient; + break; + } + // zot/nomad is harder because we will need to match the portable_id to the mention url + // and won't be able to perform duplicate detection + $r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_id_url = '%s' and hubloc_deleted = 0", + dbesc($recipient), + dbesc($term['url']) + ); + if ($r && !in_array($recipient, $result)) { + $result[] = $recipient; + break; + } + } } } - if ($deliverable && $accepting) { - $result[] = $x; + + if ($deliverable && $accepting && !in_array($recipient, $result)) { + $result[] = $recipient; } } } diff --git a/src/Daemon/Notifier.php b/src/Daemon/Notifier.php index 975093eca..9c4242240 100644 --- a/src/Daemon/Notifier.php +++ b/src/Daemon/Notifier.php @@ -444,7 +444,7 @@ class Notifier implements DaemonInterface else { $sendto = array_merge($sendto, self::getConversationAudience($parent_item)); } - self::$recipients = check_deliver_permissions($target_item['uid'], $sendto); + self::$recipients = check_deliver_permissions($target_item, $sendto); logger('followup relay (upstream delivery)', LOGGER_DEBUG); logger('replyto: upstream recipients ' . print_r(self::$recipients, true), LOGGER_DEBUG); @@ -497,7 +497,7 @@ class Notifier implements DaemonInterface foreach ($r as $rv) { self::$recipients[] = $rv['abook_xchan']; } - self::$recipients = check_deliver_permissions($target_item['uid'], self::$recipients); + self::$recipients = check_deliver_permissions($target_item, self::$recipients); } } elseif (($audience & AUDIENCE_SENDER) || ($audience & AUDIENCE_FOLLOWERS) @@ -524,7 +524,7 @@ class Notifier implements DaemonInterface } } } - self::$recipients = check_deliver_permissions($target_item['uid'], $sendto); + self::$recipients = check_deliver_permissions($target_item, $sendto); } else { self::$private = false;