Merge pull request #5974 from annando/ap-receiver

AP: Transmitting and receiving with non AP contacts
This commit is contained in:
Hypolite Petovan 2018-10-20 07:42:54 -04:00 committed by GitHub
commit ec9f1563f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 46 deletions

View file

@ -41,7 +41,7 @@ define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily'); define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily');
define('FRIENDICA_VERSION', '2018.12-dev'); define('FRIENDICA_VERSION', '2018.12-dev');
define('DFRN_PROTOCOL_VERSION', '2.23'); define('DFRN_PROTOCOL_VERSION', '2.23');
define('DB_UPDATE_VERSION', 1288); define('DB_UPDATE_VERSION', 1289);
define('NEW_UPDATE_ROUTINE_VERSION', 1170); define('NEW_UPDATE_ROUTINE_VERSION', 1170);
/** /**

View file

@ -40,6 +40,7 @@
"indexes": { "indexes": {
"PRIMARY": ["url"], "PRIMARY": ["url"],
"addr": ["addr(32)"], "addr": ["addr(32)"],
"alias": ["alias(190)"],
"url": ["followers(190)"] "url": ["followers(190)"]
} }
}, },

View file

@ -419,8 +419,9 @@ class Receiver
} }
if (in_array($receiver, [$followers, self::PUBLIC_COLLECTION]) && !empty($actor)) { if (in_array($receiver, [$followers, self::PUBLIC_COLLECTION]) && !empty($actor)) {
$networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS];
$condition = ['nurl' => normalise_link($actor), 'rel' => [Contact::SHARING, Contact::FRIEND], $condition = ['nurl' => normalise_link($actor), 'rel' => [Contact::SHARING, Contact::FRIEND],
'network' => Protocol::ACTIVITYPUB, 'archive' => false, 'pending' => false]; 'network' => $networks, 'archive' => false, 'pending' => false];
$contacts = DBA::select('contact', ['uid'], $condition); $contacts = DBA::select('contact', ['uid'], $condition);
while ($contact = DBA::fetch($contacts)) { while ($contact = DBA::fetch($contacts)) {
if ($contact['uid'] != 0) { if ($contact['uid'] != 0) {

View file

@ -308,6 +308,12 @@ class Transmitter
*/ */
private static function createPermissionBlockForItem($item) private static function createPermissionBlockForItem($item)
{ {
// Will be activated in a later step
// $networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS];
// For now only send to these contacts:
$networks = [Protocol::ACTIVITYPUB, Protocol::OSTATUS];
$data = ['to' => [], 'cc' => []]; $data = ['to' => [], 'cc' => []];
$data = array_merge($data, self::fetchPermissionBlockFromConversation($item)); $data = array_merge($data, self::fetchPermissionBlockFromConversation($item));
@ -316,8 +322,6 @@ class Transmitter
$terms = Term::tagArrayFromItemId($item['id'], TERM_MENTION); $terms = Term::tagArrayFromItemId($item['id'], TERM_MENTION);
$contacts[$item['author-link']] = $item['author-link'];
if (!$item['private']) { if (!$item['private']) {
$data['to'][] = ActivityPub::PUBLIC_COLLECTION; $data['to'][] = ActivityPub::PUBLIC_COLLECTION;
if (!empty($actor_profile['followers'])) { if (!empty($actor_profile['followers'])) {
@ -326,13 +330,8 @@ class Transmitter
foreach ($terms as $term) { foreach ($terms as $term) {
$profile = APContact::getByURL($term['url'], false); $profile = APContact::getByURL($term['url'], false);
if (!empty($profile) && empty($contacts[$profile['url']])) { if (!empty($profile)) {
$data['to'][] = $profile['url']; $data['to'][] = $profile['url'];
$contacts[$profile['url']] = $profile['url'];
if (($key = array_search($profile['url'], $data['cc'])) !== false) {
unset($data['cc'][$key]);
}
} }
} }
} else { } else {
@ -343,21 +342,17 @@ class Transmitter
foreach ($terms as $term) { foreach ($terms as $term) {
$cid = Contact::getIdForURL($term['url'], $item['uid']); $cid = Contact::getIdForURL($term['url'], $item['uid']);
if (!empty($cid) && in_array($cid, $receiver_list)) { if (!empty($cid) && in_array($cid, $receiver_list)) {
$contact = DBA::selectFirst('contact', ['url'], ['id' => $cid, 'network' => Protocol::ACTIVITYPUB]); $contact = DBA::selectFirst('contact', ['url'], ['id' => $cid, 'network' => $networks]);
$data['to'][] = $contact['url']; if (DBA::isResult($contact) && !empty($profile = APContact::getByURL($contact['url'], false))) {
$contacts[$contact['url']] = $contact['url']; $data['to'][] = $profile['url'];
if (($key = array_search($profile['url'], $data['cc'])) !== false) {
unset($data['cc'][$key]);
} }
} }
} }
foreach ($receiver_list as $receiver) { foreach ($receiver_list as $receiver) {
$contact = DBA::selectFirst('contact', ['url'], ['id' => $receiver, 'network' => Protocol::ACTIVITYPUB]); $contact = DBA::selectFirst('contact', ['url'], ['id' => $receiver, 'network' => $networks]);
if (DBA::isResult($contact) && empty($contacts[$contact['url']])) { if (DBA::isResult($contact) && !empty($profile = APContact::getByURL($contact['url'], false))) {
$data['cc'][] = $contact['url']; $data['cc'][] = $profile['url'];
$contacts[$contact['url']] = $contact['url'];
} }
} }
} }
@ -370,32 +365,28 @@ class Transmitter
} }
$profile = APContact::getByURL($parent['author-link'], false); $profile = APContact::getByURL($parent['author-link'], false);
if (!empty($profile) && ($parent['uri'] == $item['thr-parent'])) { if (!empty($profile)) {
$data['to'][] = $profile['url']; if ($parent['uri'] == $item['thr-parent']) {
$contacts[$profile['url']] = $profile['url']; $data['to'][] = $profile['url'];
} else {
if (($key = array_search($profile['url'], $data['cc'])) !== false) { $data['cc'][] = $profile['url'];
unset($data['cc'][$key]);
} }
} }
if (!empty($profile) && empty($contacts[$profile['url']])) {
$data['cc'][] = $profile['url'];
$contacts[$profile['url']] = $profile['url'];
}
if ($item['gravity'] != GRAVITY_PARENT) { if ($item['gravity'] != GRAVITY_PARENT) {
continue; continue;
} }
$profile = APContact::getByURL($parent['owner-link'], false); $profile = APContact::getByURL($parent['owner-link'], false);
if (!empty($profile) && empty($contacts[$profile['url']])) { if (!empty($profile)) {
$data['cc'][] = $profile['url']; $data['cc'][] = $profile['url'];
$contacts[$profile['url']] = $profile['url'];
} }
} }
DBA::close($parents); DBA::close($parents);
$data['to'] = array_unique($data['to']);
$data['cc'] = array_unique($data['cc']);
if (($key = array_search($item['author-link'], $data['to'])) !== false) { if (($key = array_search($item['author-link'], $data['to'])) !== false) {
unset($data['to'][$key]); unset($data['to'][$key]);
} }
@ -404,30 +395,50 @@ class Transmitter
unset($data['cc'][$key]); unset($data['cc'][$key]);
} }
return ['to' => array_values(array_unique($data['to'])), 'cc' => array_values(array_unique($data['cc']))]; foreach ($data['to'] as $to) {
if (($key = array_search($to, $data['cc'])) !== false) {
unset($data['cc'][$key]);
}
}
return ['to' => array_values($data['to']), 'cc' => array_values($data['cc'])];
} }
/** /**
* Fetches a list of inboxes of followers of a given user * Fetches a list of inboxes of followers of a given user
* *
* @param integer $uid User ID * @param integer $uid User ID
* @param boolean $personal fetch personal inboxes
* *
* @return array of follower inboxes * @return array of follower inboxes
*/ */
public static function fetchTargetInboxesforUser($uid) public static function fetchTargetInboxesforUser($uid, $personal = false)
{ {
$inboxes = []; $inboxes = [];
$condition = ['uid' => $uid, 'network' => Protocol::ACTIVITYPUB, 'archive' => false, 'pending' => false]; // Will be activated in a later step
// $networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS];
// For now only send to these contacts:
$networks = [Protocol::ACTIVITYPUB, Protocol::OSTATUS];
$condition = ['uid' => $uid, 'network' => $networks, 'archive' => false, 'pending' => false];
if (!empty($uid)) { if (!empty($uid)) {
$condition['rel'] = [Contact::FOLLOWER, Contact::FRIEND]; $condition['rel'] = [Contact::FOLLOWER, Contact::FRIEND];
} }
$contacts = DBA::select('contact', ['notify', 'batch'], $condition); $contacts = DBA::select('contact', ['url'], $condition);
while ($contact = DBA::fetch($contacts)) { while ($contact = DBA::fetch($contacts)) {
$contact = defaults($contact, 'batch', $contact['notify']); $profile = APContact::getByURL($contact['url'], false);
$inboxes[$contact] = $contact; if (!empty($profile)) {
if (empty($profile['sharedinbox']) || $personal) {
$target = $profile['inbox'];
} else {
$target = $profile['sharedinbox'];
}
$inboxes[$target] = $target;
}
} }
DBA::close($contacts); DBA::close($contacts);
@ -439,10 +450,11 @@ class Transmitter
* *
* @param array $item * @param array $item
* @param integer $uid User ID * @param integer $uid User ID
* @param boolean $personal fetch personal inboxes
* *
* @return array with inboxes * @return array with inboxes
*/ */
public static function fetchTargetInboxes($item, $uid) public static function fetchTargetInboxes($item, $uid, $personal = false)
{ {
$permissions = self::createPermissionBlockForItem($item); $permissions = self::createPermissionBlockForItem($item);
if (empty($permissions)) { if (empty($permissions)) {
@ -452,9 +464,9 @@ class Transmitter
$inboxes = []; $inboxes = [];
if ($item['gravity'] == GRAVITY_ACTIVITY) { if ($item['gravity'] == GRAVITY_ACTIVITY) {
$item_profile = APContact::getByURL($item['author-link']); $item_profile = APContact::getByURL($item['author-link'], false);
} else { } else {
$item_profile = APContact::getByURL($item['owner-link']); $item_profile = APContact::getByURL($item['owner-link'], false);
} }
foreach (['to', 'cc', 'bto', 'bcc'] as $element) { foreach (['to', 'cc', 'bto', 'bcc'] as $element) {
@ -464,11 +476,15 @@ class Transmitter
foreach ($permissions[$element] as $receiver) { foreach ($permissions[$element] as $receiver) {
if ($receiver == $item_profile['followers']) { if ($receiver == $item_profile['followers']) {
$inboxes = self::fetchTargetInboxesforUser($uid); $inboxes = self::fetchTargetInboxesforUser($uid, $personal);
} else { } else {
$profile = APContact::getByURL($receiver); $profile = APContact::getByURL($receiver, false);
if (!empty($profile)) { if (!empty($profile)) {
$target = defaults($profile, 'sharedinbox', $profile['inbox']); if (empty($profile['sharedinbox']) || $personal) {
$target = $profile['inbox'];
} else {
$target = $profile['sharedinbox'];
}
$inboxes[$target] = $target; $inboxes[$target] = $target;
} }
} }

View file

@ -512,6 +512,7 @@ class Notifier
private static function activityPubDelivery($a, $cmd, $item_id, $uid, $target_item, $parent) private static function activityPubDelivery($a, $cmd, $item_id, $uid, $target_item, $parent)
{ {
$inboxes = []; $inboxes = [];
$personal = false;
if ($target_item['origin']) { if ($target_item['origin']) {
$inboxes = ActivityPub\Transmitter::fetchTargetInboxes($target_item, $uid); $inboxes = ActivityPub\Transmitter::fetchTargetInboxes($target_item, $uid);
@ -520,11 +521,14 @@ class Notifier
logger('Remote item ' . $item_id . ' with URL ' . $target_item['uri'] . ' is no AP post. It will not be distributed.', LOGGER_DEBUG); logger('Remote item ' . $item_id . ' with URL ' . $target_item['uri'] . ' is no AP post. It will not be distributed.', LOGGER_DEBUG);
return; return;
} else { } else {
// Remote items are transmitted via the personal inboxes.
// Doing so ensures that the dedicated receiver will get the message.
$personal = true;
logger('Remote item ' . $item_id . ' with URL ' . $target_item['uri'] . ' will be distributed.', LOGGER_DEBUG); logger('Remote item ' . $item_id . ' with URL ' . $target_item['uri'] . ' will be distributed.', LOGGER_DEBUG);
} }
if ($parent['origin']) { if ($parent['origin']) {
$parent_inboxes = ActivityPub\Transmitter::fetchTargetInboxes($parent, $uid); $parent_inboxes = ActivityPub\Transmitter::fetchTargetInboxes($parent, $uid, $personal);
$inboxes = array_merge($inboxes, $parent_inboxes); $inboxes = array_merge($inboxes, $parent_inboxes);
} }