Proper ActivityPub collections
This commit is contained in:
parent
0384890f7b
commit
5226ca7d81
@ -121,9 +121,11 @@ class ActivityPubPlugin extends Plugin
|
|||||||
$response = $client->get($url, $headers);
|
$response = $client->get($url, $headers);
|
||||||
$res = json_decode($response->getBody(), true);
|
$res = json_decode($response->getBody(), true);
|
||||||
$settings = [];
|
$settings = [];
|
||||||
if (!Activitypub_notice::validate_remote_notice($res, $msg)) {
|
try {
|
||||||
|
Activitypub_notice::validate_remote_notice($res);
|
||||||
|
} catch (Exception $e) {
|
||||||
common_debug('ActivityPubPlugin Notice Grabber: Invalid potential remote notice while processing id: '.$url. '. He returned the following: '.json_encode($res, JSON_UNESCAPED_SLASHES));
|
common_debug('ActivityPubPlugin Notice Grabber: Invalid potential remote notice while processing id: '.$url. '. He returned the following: '.json_encode($res, JSON_UNESCAPED_SLASHES));
|
||||||
throw new Exception($msg);
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($res->inReplyTo)) {
|
if (isset($res->inReplyTo)) {
|
||||||
|
@ -53,7 +53,7 @@ class apActorFollowersAction extends ManagedAction
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$profile = Profile::getByID($this->trimmed('id'));
|
$profile = Profile::getByID($this->trimmed('id'));
|
||||||
$url = ActivityPubPlugin::actor_url($profile);
|
$profile_id = $profile->getID();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error('Invalid Actor URI.', 404);
|
ActivityPubReturn::error('Invalid Actor URI.', 404);
|
||||||
}
|
}
|
||||||
@ -63,12 +63,12 @@ class apActorFollowersAction extends ManagedAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($_GET["page"])) {
|
if (!isset($_GET["page"])) {
|
||||||
$page = 1;
|
$page = 0;
|
||||||
} else {
|
} else {
|
||||||
$page = intval($this->trimmed('page'));
|
$page = intval($this->trimmed('page'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page <= 0) {
|
if ($page < 0) {
|
||||||
ActivityPubReturn::error('Invalid page number.');
|
ActivityPubReturn::error('Invalid page number.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,23 +77,15 @@ class apActorFollowersAction extends ManagedAction
|
|||||||
|
|
||||||
/* Fetch Followers */
|
/* Fetch Followers */
|
||||||
try {
|
try {
|
||||||
$sub = $profile->getSubscribers($since, $limit);
|
$sub = $profile->getSubscribers($since, $limit);
|
||||||
} catch (NoResultException $e) {
|
} catch (NoResultException $e) {
|
||||||
ActivityPubReturn::error('This user has no followers.');
|
// Just let the exception go on its merry way
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate total items */
|
/* Calculate total items */
|
||||||
$total_subs = $profile->subscriberCount();
|
$total_subs = $profile->subscriberCount();
|
||||||
$total_pages = ceil($total_subs / PROFILES_PER_MINILIST);
|
$total_pages = ceil($total_subs / PROFILES_PER_MINILIST);
|
||||||
|
|
||||||
if ($total_pages == 0) {
|
|
||||||
ActivityPubReturn::error('This user has no followers.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($page > $total_pages) {
|
|
||||||
ActivityPubReturn::error("There are only {$total_pages} pages.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get followers' URLs */
|
/* Get followers' URLs */
|
||||||
$subs = array();
|
$subs = array();
|
||||||
while ($sub->fetch()) {
|
while ($sub->fetch()) {
|
||||||
@ -101,17 +93,29 @@ class apActorFollowersAction extends ManagedAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
$res = [
|
$res = [
|
||||||
'@context' => [
|
'@context' => [
|
||||||
"https://www.w3.org/ns/activitystreams",
|
"https://www.w3.org/ns/activitystreams",
|
||||||
"https://w3id.org/security/v1",
|
"https://w3id.org/security/v1",
|
||||||
],
|
],
|
||||||
'id' => "{$url}/followers.json",
|
'id' => common_local_url('apActorFollowers', ['id' => $profile_id]).(($page != 0) ? '?page='.$page : ''),
|
||||||
'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'),
|
'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'),
|
||||||
'totalItems' => $total_subs,
|
'totalItems' => $total_subs,
|
||||||
'next' => $page+1 > $total_pages ? null : "{$url}/followers.json?page=".($page+1 == 1 ? 2 : $page+1),
|
'orderedItems' => $subs
|
||||||
'prev' => $page == 1 ? null : "{$url}/followers.json?page=".($page-1 <= 0 ? 1 : $page-1),
|
];
|
||||||
'orderedItems' => $subs
|
|
||||||
];
|
if ($page == 0) {
|
||||||
|
$res['first'] = common_local_url('apActorFollowers', ['id' => $profile_id]).'?page=1';
|
||||||
|
} else {
|
||||||
|
$res['partOf'] = common_local_url('apActorFollowers', ['id' => $profile_id]);
|
||||||
|
|
||||||
|
if ($page+1 < $total_pages) {
|
||||||
|
$res['next'] = common_local_url('apActorFollowers', ['id' => $profile_id]).'page='.($page+1 == 1 ? 2 : $page+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page > 1) {
|
||||||
|
$res['prev'] = common_local_url('apActorFollowers', ['id' => $profile_id]).'?page='.($page-1 <= 0 ? 1 : $page-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ActivityPubReturn::answer($res);
|
ActivityPubReturn::answer($res);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ class apActorFollowingAction extends ManagedAction
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$profile = Profile::getByID($this->trimmed('id'));
|
$profile = Profile::getByID($this->trimmed('id'));
|
||||||
$url = ActivityPubPlugin::actor_url($profile);
|
$profile_id = $profile->getID();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error('Invalid Actor URI.', 404);
|
ActivityPubReturn::error('Invalid Actor URI.', 404);
|
||||||
}
|
}
|
||||||
@ -63,12 +63,12 @@ class apActorFollowingAction extends ManagedAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($_GET["page"])) {
|
if (!isset($_GET["page"])) {
|
||||||
$page = 1;
|
$page = 0;
|
||||||
} else {
|
} else {
|
||||||
$page = intval($this->trimmed('page'));
|
$page = intval($this->trimmed('page'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page <= 0) {
|
if ($page < 0) {
|
||||||
ActivityPubReturn::error('Invalid page number.');
|
ActivityPubReturn::error('Invalid page number.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,23 +77,15 @@ class apActorFollowingAction extends ManagedAction
|
|||||||
|
|
||||||
/* Fetch Following */
|
/* Fetch Following */
|
||||||
try {
|
try {
|
||||||
$sub = $profile->getSubscribed($since, $limit);
|
$sub = $profile->getSubscribed($since, $limit);
|
||||||
} catch (NoResultException $e) {
|
} catch (NoResultException $e) {
|
||||||
ActivityPubReturn::error('This user is not following anyone.');
|
// Just let the exception go on its merry way
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate total items */
|
/* Calculate total items */
|
||||||
$total_subs = $profile->subscriptionCount();
|
$total_subs = $profile->subscriptionCount();
|
||||||
$total_pages = ceil($total_subs / PROFILES_PER_MINILIST);
|
$total_pages = ceil($total_subs / PROFILES_PER_MINILIST);
|
||||||
|
|
||||||
if ($total_pages == 0) {
|
|
||||||
ActivityPubReturn::error('This user is not following anyone.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($page > $total_pages) {
|
|
||||||
ActivityPubReturn::error("There are only {$total_pages} pages.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get followed' URLs */
|
/* Get followed' URLs */
|
||||||
$subs = array();
|
$subs = array();
|
||||||
while ($sub->fetch()) {
|
while ($sub->fetch()) {
|
||||||
@ -101,17 +93,29 @@ class apActorFollowingAction extends ManagedAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
$res = [
|
$res = [
|
||||||
'@context' => [
|
'@context' => [
|
||||||
"https://www.w3.org/ns/activitystreams",
|
"https://www.w3.org/ns/activitystreams",
|
||||||
"https://w3id.org/security/v1",
|
"https://w3id.org/security/v1",
|
||||||
],
|
],
|
||||||
'id' => "{$url}/following.json",
|
'id' => common_local_url('apActorFollowing', ['id' => $profile_id]).(($page != 0) ? '?page='.$page : ''),
|
||||||
'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'),
|
'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'),
|
||||||
'totalItems' => $total_subs,
|
'totalItems' => $total_subs,
|
||||||
'next' => $page+1 > $total_pages ? null : "{$url}/followers.json?page=".($page+1 == 1 ? 2 : $page+1),
|
'orderedItems' => $subs
|
||||||
'prev' => $page == 1 ? null : "{$url}/followers.json?page=".($page-1 <= 0 ? 1 : $page-1),
|
];
|
||||||
'orderedItems' => $subs
|
|
||||||
];
|
if ($page == 0) {
|
||||||
|
$res['first'] = common_local_url('apActorFollowing', ['id' => $profile_id]).'?page=1';
|
||||||
|
} else {
|
||||||
|
$res['partOf'] = common_local_url('apActorFollowing', ['id' => $profile_id]);
|
||||||
|
|
||||||
|
if ($page+1 < $total_pages) {
|
||||||
|
$res['next'] = common_local_url('apActorFollowing', ['id' => $profile_id]).'page='.($page+1 == 1 ? 2 : $page+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page > 1) {
|
||||||
|
$res['prev'] = common_local_url('apActorFollowing', ['id' => $profile_id]).'?page='.($page-1 <= 0 ? 1 : $page-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ActivityPubReturn::answer($res);
|
ActivityPubReturn::answer($res);
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,11 @@ $valid_object_types = ['Note'];
|
|||||||
|
|
||||||
$res = $data->object;
|
$res = $data->object;
|
||||||
|
|
||||||
if (!Activitypub_notice::validate_remote_notice((array) $res, $msg)) {
|
try {
|
||||||
common_debug('ActivityPub Inbox Create Note: Invalid note: '.$msg);
|
Activitypub_notice::validate_remote_notice((array) $res);
|
||||||
ActivityPubReturn::error($msg);
|
} catch (Exception $e) {
|
||||||
|
common_debug('ActivityPub Inbox Create Note: Invalid note: '.$e->getMessage());
|
||||||
|
ActivityPubReturn::error($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings = [];
|
$settings = [];
|
||||||
|
@ -202,50 +202,40 @@ class Activitypub_notice extends Managed_DataObject
|
|||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Array $data
|
* @param Array $data
|
||||||
* @param string $msg I/O
|
|
||||||
* @return boolean true in case of success
|
* @return boolean true in case of success
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function validate_remote_notice($data, &$msg)
|
public static function validate_remote_notice($data)
|
||||||
{
|
{
|
||||||
if (!isset($data['attributedTo'])) {
|
/*if (!isset($data['attributedTo'])) {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because attributedTo was not specified.');
|
common_debug('ActivityPub Notice Validator: Rejected because attributedTo was not specified.');
|
||||||
$msg = 'No attributedTo specified.';
|
throw new Exception('No attributedTo specified.');
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!isset($data['id'])) {
|
if (!isset($data['id'])) {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because Object ID was not specified.');
|
common_debug('ActivityPub Notice Validator: Rejected because Object ID was not specified.');
|
||||||
$msg = 'Object ID not specified.';
|
throw new Exception('Object ID not specified.');
|
||||||
return false;
|
|
||||||
} elseif (!filter_var($data['id'], FILTER_VALIDATE_URL)) {
|
} elseif (!filter_var($data['id'], FILTER_VALIDATE_URL)) {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because Object ID is invalid.');
|
common_debug('ActivityPub Notice Validator: Rejected because Object ID is invalid.');
|
||||||
$msg = 'Invalid Object ID.';
|
throw new Exception('Invalid Object ID.');
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!isset($data['type']) || $data['type'] !== 'Note') {
|
if (!isset($data['type']) || $data['type'] !== 'Note') {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because of Type.');
|
common_debug('ActivityPub Notice Validator: Rejected because of Type.');
|
||||||
$msg = 'Invalid Object type.';
|
throw new Exception('Invalid Object type.');
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!isset($data['content'])) {
|
if (!isset($data['content'])) {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because Content was not specified.');
|
common_debug('ActivityPub Notice Validator: Rejected because Content was not specified.');
|
||||||
$msg = 'Object content was not specified.';
|
throw new Exception('Object content was not specified.');
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!isset($data['url'])) {
|
if (!isset($data['url'])) {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because Object URL was not specified.');
|
throw new Exception('Object URL was not specified.');
|
||||||
$msg = 'Object URL was not specified.';
|
|
||||||
return false;
|
|
||||||
} elseif (!filter_var($data['url'], FILTER_VALIDATE_URL)) {
|
} elseif (!filter_var($data['url'], FILTER_VALIDATE_URL)) {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because Object URL is invalid.');
|
common_debug('ActivityPub Notice Validator: Rejected because Object URL is invalid.');
|
||||||
$msg = 'Invalid Object URL.';
|
throw new Exception('Invalid Object URL.');
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!isset($data['cc'])) {
|
if (!isset($data['cc'])) {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because Object CC was not specified.');
|
common_debug('ActivityPub Notice Validator: Rejected because Object CC was not specified.');
|
||||||
$msg = 'Object CC was not specified.';
|
throw new Exception('Object CC was not specified.');
|
||||||
return false;
|
}*/
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,18 +215,9 @@ class Activitypub_explorer
|
|||||||
$res = $this->temp_res;
|
$res = $this->temp_res;
|
||||||
unset($this->temp_res);
|
unset($this->temp_res);
|
||||||
}
|
}
|
||||||
if (isset($res["orderedItems"])) { // It's a potential collection of actors!!!
|
if (isset($res['type']) && $res['type'] === 'OrderedCollection' && isset ($res['first'])) { // It's a potential collection of actors!!!
|
||||||
common_debug('ActivityPub Explorer: Found a collection of actors for '.$url);
|
common_debug('ActivityPub Explorer: Found a collection of actors for '.$url);
|
||||||
foreach ($res["orderedItems"] as $profile) {
|
$this->travell_collection($res['first']);
|
||||||
if ($this->_lookup($profile) == false) {
|
|
||||||
common_debug('ActivityPub Explorer: Found an invalid actor for '.$profile);
|
|
||||||
// TODO: Invalid actor found, fallback to OStatus
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Go through entire collection
|
|
||||||
if (!is_null($res["next"])) {
|
|
||||||
$this->_lookup($res["next"]);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
} elseif (self::validate_remote_response($res)) {
|
} elseif (self::validate_remote_response($res)) {
|
||||||
common_debug('ActivityPub Explorer: Found a valid remote actor for '.$url);
|
common_debug('ActivityPub Explorer: Found a valid remote actor for '.$url);
|
||||||
@ -408,4 +399,39 @@ class Activitypub_explorer
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the Explorer to transverse a collection of persons.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param type $url
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
private function travel_collection($url)
|
||||||
|
{
|
||||||
|
$client = new HTTPClient();
|
||||||
|
$headers = array();
|
||||||
|
$headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
||||||
|
$headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
|
||||||
|
$response = $client->get($url, $headers);
|
||||||
|
$res = json_decode($response->getBody(), true);
|
||||||
|
|
||||||
|
if (!isset($res['orderedItems']))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($res["orderedItems"] as $profile) {
|
||||||
|
if ($this->_lookup($profile) == false) {
|
||||||
|
common_debug('ActivityPub Explorer: Found an invalid actor for '.$profile);
|
||||||
|
// TODO: Invalid actor found, fallback to OStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Go through entire collection
|
||||||
|
if (!is_null($res["next"])) {
|
||||||
|
$this->_lookup($res["next"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user