Update person, undo activity and improved security checks
This commit is contained in:
parent
8c7e5bb776
commit
094c27add6
1 changed files with 79 additions and 12 deletions
|
@ -43,16 +43,30 @@ use Friendica\Core\Config;
|
||||||
* To-do:
|
* To-do:
|
||||||
*
|
*
|
||||||
* Receiver:
|
* Receiver:
|
||||||
* - Activities: Update (Notes, Person), Delete (Person, Activities, Notes)
|
* - Update Note
|
||||||
* - Object Types: Person, Tombstome
|
* - Delete Note
|
||||||
|
* - Delete Person
|
||||||
|
* - Undo Announce
|
||||||
|
* - Reject Follow
|
||||||
|
* - Undo Accept
|
||||||
|
* - Undo Follow
|
||||||
|
* - Add
|
||||||
|
* - Create Image
|
||||||
|
* - Create Video
|
||||||
|
* - Event
|
||||||
|
* - Remove
|
||||||
|
* - Block
|
||||||
|
* - Flag
|
||||||
*
|
*
|
||||||
* Transmitter:
|
* Transmitter:
|
||||||
* - Activities: Announce, Update (Person)
|
* - Announce
|
||||||
* - Object Tyoes: Person
|
* - Undo Announce
|
||||||
|
* - Update Person
|
||||||
|
* - Reject Follow
|
||||||
|
* - Event
|
||||||
*
|
*
|
||||||
* General:
|
* General:
|
||||||
* - Queueing unsucessful deliveries
|
* - Queueing unsucessful deliveries
|
||||||
* - Event support
|
|
||||||
* - Polling the outboxes for missing content?
|
* - Polling the outboxes for missing content?
|
||||||
*/
|
*/
|
||||||
class ActivityPub
|
class ActivityPub
|
||||||
|
@ -270,7 +284,7 @@ class ActivityPub
|
||||||
$exclude[] = $item['owner-link'];
|
$exclude[] = $item['owner-link'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$permissions = [];
|
$permissions['to'][] = $actor;
|
||||||
|
|
||||||
$elements = ['to', 'cc', 'bto', 'bcc'];
|
$elements = ['to', 'cc', 'bto', 'bcc'];
|
||||||
foreach ($elements as $element) {
|
foreach ($elements as $element) {
|
||||||
|
@ -280,6 +294,7 @@ class ActivityPub
|
||||||
if (is_string($activity[$element])) {
|
if (is_string($activity[$element])) {
|
||||||
$activity[$element] = [$activity[$element]];
|
$activity[$element] = [$activity[$element]];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($activity[$element] as $receiver) {
|
foreach ($activity[$element] as $receiver) {
|
||||||
if ($receiver == $profile['followers'] && !empty($item_profile['followers'])) {
|
if ($receiver == $profile['followers'] && !empty($item_profile['followers'])) {
|
||||||
$receiver = $item_profile['followers'];
|
$receiver = $item_profile['followers'];
|
||||||
|
@ -346,10 +361,13 @@ class ActivityPub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is to decide whether we should include all profiles in a thread to the list of receivers
|
|
||||||
/*
|
|
||||||
$parents = Item::select(['author-link', 'owner-link', 'gravity'], ['parent' => $item['parent']]);
|
$parents = Item::select(['author-link', 'owner-link', 'gravity'], ['parent' => $item['parent']]);
|
||||||
while ($parent = Item::fetch($parents)) {
|
while ($parent = Item::fetch($parents)) {
|
||||||
|
// Don't include data from future posts
|
||||||
|
if ($parent['id'] >= $item['id']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$profile = self::fetchprofile($parent['author-link'], false);
|
$profile = self::fetchprofile($parent['author-link'], false);
|
||||||
if (!empty($profile) && empty($contacts[$profile['url']])) {
|
if (!empty($profile) && empty($contacts[$profile['url']])) {
|
||||||
$data['cc'][] = $profile['url'];
|
$data['cc'][] = $profile['url'];
|
||||||
|
@ -367,7 +385,7 @@ class ActivityPub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBA::close($parents);
|
DBA::close($parents);
|
||||||
*/
|
|
||||||
if (empty($data['to'])) {
|
if (empty($data['to'])) {
|
||||||
$data['to'] = $data['cc'];
|
$data['to'] = $data['cc'];
|
||||||
$data['cc'] = [];
|
$data['cc'] = [];
|
||||||
|
@ -952,7 +970,7 @@ class ActivityPub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function prepareObjectData($activity, $uid, $trust_source)
|
private static function prepareObjectData($activity, $uid, &$trust_source)
|
||||||
{
|
{
|
||||||
$actor = JsonLD::fetchElement($activity, 'actor', 'id');
|
$actor = JsonLD::fetchElement($activity, 'actor', 'id');
|
||||||
if (empty($actor)) {
|
if (empty($actor)) {
|
||||||
|
@ -982,12 +1000,18 @@ class ActivityPub
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the content only on activities where this matters
|
// Fetch the content only on activities where this matters
|
||||||
if (in_array($activity['type'], ['Create', 'Update', 'Announce'])) {
|
if (in_array($activity['type'], ['Create', 'Announce'])) {
|
||||||
$object_data = self::fetchObject($object_url, $activity['object'], $trust_source);
|
$object_data = self::fetchObject($object_url, $activity['object'], $trust_source);
|
||||||
if (empty($object_data)) {
|
if (empty($object_data)) {
|
||||||
logger("Object data couldn't be processed", LOGGER_DEBUG);
|
logger("Object data couldn't be processed", LOGGER_DEBUG);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
// We had been able to retrieve the object data - so we can trust the source
|
||||||
|
$trust_source = true;
|
||||||
|
} elseif ($activity['type'] == 'Update') {
|
||||||
|
$object_data = [];
|
||||||
|
$object_data['object_type'] = JsonLD::fetchElement($activity, 'object', 'type');
|
||||||
|
$object_data['object'] = $activity['object'];
|
||||||
} elseif ($activity['type'] == 'Accept') {
|
} elseif ($activity['type'] == 'Accept') {
|
||||||
$object_data = [];
|
$object_data = [];
|
||||||
$object_data['object_type'] = JsonLD::fetchElement($activity, 'object', 'type');
|
$object_data['object_type'] = JsonLD::fetchElement($activity, 'object', 'type');
|
||||||
|
@ -995,7 +1019,11 @@ class ActivityPub
|
||||||
} elseif ($activity['type'] == 'Undo') {
|
} elseif ($activity['type'] == 'Undo') {
|
||||||
$object_data = [];
|
$object_data = [];
|
||||||
$object_data['object_type'] = JsonLD::fetchElement($activity, 'object', 'type');
|
$object_data['object_type'] = JsonLD::fetchElement($activity, 'object', 'type');
|
||||||
$object_data['object'] = JsonLD::fetchElement($activity, 'object', 'object');
|
if ($object_data['object_type'] == 'Follow') {
|
||||||
|
$object_data['object'] = JsonLD::fetchElement($activity, 'object', 'object');
|
||||||
|
} else {
|
||||||
|
$object_data['object'] = $activity['object'];
|
||||||
|
}
|
||||||
} elseif (in_array($activity['type'], ['Like', 'Dislike'])) {
|
} elseif (in_array($activity['type'], ['Like', 'Dislike'])) {
|
||||||
// Create a mostly empty array out of the activity data (instead of the object).
|
// Create a mostly empty array out of the activity data (instead of the object).
|
||||||
// This way we later don't have to check for the existence of ech individual array element.
|
// This way we later don't have to check for the existence of ech individual array element.
|
||||||
|
@ -1045,12 +1073,17 @@ class ActivityPub
|
||||||
|
|
||||||
logger('Processing activity: ' . $activity['type'], LOGGER_DEBUG);
|
logger('Processing activity: ' . $activity['type'], LOGGER_DEBUG);
|
||||||
|
|
||||||
|
// $trust_source is called by reference and is set to true if the content was retrieved successfully
|
||||||
$object_data = self::prepareObjectData($activity, $uid, $trust_source);
|
$object_data = self::prepareObjectData($activity, $uid, $trust_source);
|
||||||
if (empty($object_data)) {
|
if (empty($object_data)) {
|
||||||
logger('No object data found', LOGGER_DEBUG);
|
logger('No object data found', LOGGER_DEBUG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!trust_source) {
|
||||||
|
logger('No trust for activity type "' . $activity['type'] . '", so we quit now.', LOGGER_DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
switch ($activity['type']) {
|
switch ($activity['type']) {
|
||||||
case 'Create':
|
case 'Create':
|
||||||
case 'Announce':
|
case 'Announce':
|
||||||
|
@ -1066,6 +1099,9 @@ class ActivityPub
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Update':
|
case 'Update':
|
||||||
|
if (in_array($object_data['object_type'], ['Person', 'Organization', 'Service', 'Group', 'Application'])) {
|
||||||
|
self::updatePerson($object_data, $body);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Delete':
|
case 'Delete':
|
||||||
|
@ -1084,6 +1120,8 @@ class ActivityPub
|
||||||
case 'Undo':
|
case 'Undo':
|
||||||
if ($object_data['object_type'] == 'Follow') {
|
if ($object_data['object_type'] == 'Follow') {
|
||||||
self::undoFollowUser($object_data);
|
self::undoFollowUser($object_data);
|
||||||
|
} elseif (in_array($object_data['object_type'], ['Like', 'Dislike', 'Accept', 'Reject', 'TentativeAccept'])) {
|
||||||
|
self::undoActivity($object_data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1553,6 +1591,15 @@ class ActivityPub
|
||||||
logger('Follow user ' . $uid . ' from contact ' . $cid . ' with id ' . $activity['id']);
|
logger('Follow user ' . $uid . ' from contact ' . $cid . ' with id ' . $activity['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function updatePerson($activity)
|
||||||
|
{
|
||||||
|
if (empty($activity['object']['id'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self::fetchprofile($activity['object']['id'], true);
|
||||||
|
}
|
||||||
|
|
||||||
private static function acceptFollowUser($activity)
|
private static function acceptFollowUser($activity)
|
||||||
{
|
{
|
||||||
$uid = self::getUserOfObject($activity['object']);
|
$uid = self::getUserOfObject($activity['object']);
|
||||||
|
@ -1580,6 +1627,26 @@ class ActivityPub
|
||||||
logger('Accept contact request from contact ' . $cid . ' for user ' . $uid, LOGGER_DEBUG);
|
logger('Accept contact request from contact ' . $cid . ' for user ' . $uid, LOGGER_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function undoActivity($activity)
|
||||||
|
{
|
||||||
|
$activity_url = JsonLD::fetchElement($activity, 'object', 'id');
|
||||||
|
if (empty($activity_url)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$actor = JsonLD::fetchElement($activity, 'object', 'actor');
|
||||||
|
if (empty($actor)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$author_id = Contact::getIdForURL($actor);
|
||||||
|
if (empty($author_id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item::delete(['uri' => $activity_url, 'author-id' => $author_id, 'gravity' => GRAVITY_ACTIVITY]);
|
||||||
|
}
|
||||||
|
|
||||||
private static function undoFollowUser($activity)
|
private static function undoFollowUser($activity)
|
||||||
{
|
{
|
||||||
$uid = self::getUserOfObject($activity['object']);
|
$uid = self::getUserOfObject($activity['object']);
|
||||||
|
|
Loading…
Reference in a new issue