diff --git a/ActivityPubPlugin.php b/ActivityPubPlugin.php index 570b426..fb53c6b 100755 --- a/ActivityPubPlugin.php +++ b/ActivityPubPlugin.php @@ -121,9 +121,11 @@ class ActivityPubPlugin extends Plugin $response = $client->get($url, $headers); $res = json_decode($response->getBody(), true); $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)); - throw new Exception($msg); + throw $e; } if (isset($res->inReplyTo)) { diff --git a/actions/apactorfollowers.php b/actions/apactorfollowers.php index b1cac40..4eadac7 100755 --- a/actions/apactorfollowers.php +++ b/actions/apactorfollowers.php @@ -53,7 +53,7 @@ class apActorFollowersAction extends ManagedAction { try { $profile = Profile::getByID($this->trimmed('id')); - $url = ActivityPubPlugin::actor_url($profile); + $profile_id = $profile->getID(); } catch (Exception $e) { ActivityPubReturn::error('Invalid Actor URI.', 404); } @@ -63,12 +63,12 @@ class apActorFollowersAction extends ManagedAction } if (!isset($_GET["page"])) { - $page = 1; + $page = 0; } else { $page = intval($this->trimmed('page')); } - if ($page <= 0) { + if ($page < 0) { ActivityPubReturn::error('Invalid page number.'); } @@ -77,23 +77,15 @@ class apActorFollowersAction extends ManagedAction /* Fetch Followers */ try { - $sub = $profile->getSubscribers($since, $limit); + $sub = $profile->getSubscribers($since, $limit); } catch (NoResultException $e) { - ActivityPubReturn::error('This user has no followers.'); + // Just let the exception go on its merry way } /* Calculate total items */ $total_subs = $profile->subscriberCount(); $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 */ $subs = array(); while ($sub->fetch()) { @@ -101,17 +93,29 @@ class apActorFollowersAction extends ManagedAction } $res = [ - '@context' => [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - ], - 'id' => "{$url}/followers.json", - 'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'), - 'totalItems' => $total_subs, - 'next' => $page+1 > $total_pages ? null : "{$url}/followers.json?page=".($page+1 == 1 ? 2 : $page+1), - 'prev' => $page == 1 ? null : "{$url}/followers.json?page=".($page-1 <= 0 ? 1 : $page-1), - 'orderedItems' => $subs - ]; + '@context' => [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + ], + 'id' => common_local_url('apActorFollowers', ['id' => $profile_id]).(($page != 0) ? '?page='.$page : ''), + 'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'), + 'totalItems' => $total_subs, + '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); } diff --git a/actions/apactorfollowing.php b/actions/apactorfollowing.php index 30777fc..7fa71c1 100755 --- a/actions/apactorfollowing.php +++ b/actions/apactorfollowing.php @@ -53,7 +53,7 @@ class apActorFollowingAction extends ManagedAction { try { $profile = Profile::getByID($this->trimmed('id')); - $url = ActivityPubPlugin::actor_url($profile); + $profile_id = $profile->getID(); } catch (Exception $e) { ActivityPubReturn::error('Invalid Actor URI.', 404); } @@ -63,12 +63,12 @@ class apActorFollowingAction extends ManagedAction } if (!isset($_GET["page"])) { - $page = 1; + $page = 0; } else { $page = intval($this->trimmed('page')); } - if ($page <= 0) { + if ($page < 0) { ActivityPubReturn::error('Invalid page number.'); } @@ -77,23 +77,15 @@ class apActorFollowingAction extends ManagedAction /* Fetch Following */ try { - $sub = $profile->getSubscribed($since, $limit); + $sub = $profile->getSubscribed($since, $limit); } catch (NoResultException $e) { - ActivityPubReturn::error('This user is not following anyone.'); + // Just let the exception go on its merry way } /* Calculate total items */ $total_subs = $profile->subscriptionCount(); $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 */ $subs = array(); while ($sub->fetch()) { @@ -101,17 +93,29 @@ class apActorFollowingAction extends ManagedAction } $res = [ - '@context' => [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - ], - 'id' => "{$url}/following.json", - 'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'), - 'totalItems' => $total_subs, - 'next' => $page+1 > $total_pages ? null : "{$url}/followers.json?page=".($page+1 == 1 ? 2 : $page+1), - 'prev' => $page == 1 ? null : "{$url}/followers.json?page=".($page-1 <= 0 ? 1 : $page-1), - 'orderedItems' => $subs - ]; + '@context' => [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + ], + 'id' => common_local_url('apActorFollowing', ['id' => $profile_id]).(($page != 0) ? '?page='.$page : ''), + 'type' => ($page == 0 ? 'OrderedCollection' : 'OrderedCollectionPage'), + 'totalItems' => $total_subs, + '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); } diff --git a/actions/inbox/Create.php b/actions/inbox/Create.php index 7456b4a..7a7c71a 100755 --- a/actions/inbox/Create.php +++ b/actions/inbox/Create.php @@ -33,9 +33,11 @@ $valid_object_types = ['Note']; $res = $data->object; -if (!Activitypub_notice::validate_remote_notice((array) $res, $msg)) { - common_debug('ActivityPub Inbox Create Note: Invalid note: '.$msg); - ActivityPubReturn::error($msg); +try { + Activitypub_notice::validate_remote_notice((array) $res); +} catch (Exception $e) { + common_debug('ActivityPub Inbox Create Note: Invalid note: '.$e->getMessage()); + ActivityPubReturn::error($e->getMessage()); } $settings = []; diff --git a/classes/Activitypub_notice.php b/classes/Activitypub_notice.php index 62fb5e2..07206f8 100755 --- a/classes/Activitypub_notice.php +++ b/classes/Activitypub_notice.php @@ -202,50 +202,40 @@ class Activitypub_notice extends Managed_DataObject * * @author Diogo Cordeiro * @param Array $data - * @param string $msg I/O * @return boolean true in case of success * @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.'); - $msg = 'No attributedTo specified.'; - return false; + throw new Exception('No attributedTo specified.'); } if (!isset($data['id'])) { common_debug('ActivityPub Notice Validator: Rejected because Object ID was not specified.'); - $msg = 'Object ID not specified.'; - return false; + throw new Exception('Object ID not specified.'); } elseif (!filter_var($data['id'], FILTER_VALIDATE_URL)) { common_debug('ActivityPub Notice Validator: Rejected because Object ID is invalid.'); - $msg = 'Invalid Object ID.'; - return false; + throw new Exception('Invalid Object ID.'); } if (!isset($data['type']) || $data['type'] !== 'Note') { common_debug('ActivityPub Notice Validator: Rejected because of Type.'); - $msg = 'Invalid Object type.'; - return false; + throw new Exception('Invalid Object type.'); } if (!isset($data['content'])) { common_debug('ActivityPub Notice Validator: Rejected because Content was not specified.'); - $msg = 'Object content was not specified.'; - return false; + throw new Exception('Object content was not specified.'); } if (!isset($data['url'])) { - common_debug('ActivityPub Notice Validator: Rejected because Object URL was not specified.'); - $msg = 'Object URL was not specified.'; - return false; + throw new Exception('Object URL was not specified.'); } elseif (!filter_var($data['url'], FILTER_VALIDATE_URL)) { common_debug('ActivityPub Notice Validator: Rejected because Object URL is invalid.'); - $msg = 'Invalid Object URL.'; - return false; + throw new Exception('Invalid Object URL.'); } if (!isset($data['cc'])) { common_debug('ActivityPub Notice Validator: Rejected because Object CC was not specified.'); - $msg = 'Object CC was not specified.'; - return false; - } + throw new Exception('Object CC was not specified.'); + }*/ return true; } } diff --git a/utils/explorer.php b/utils/explorer.php index c11a3cd..9079dcb 100755 --- a/utils/explorer.php +++ b/utils/explorer.php @@ -215,18 +215,9 @@ class Activitypub_explorer $res = $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); - 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"]); - } + $this->travell_collection($res['first']); return true; } elseif (self::validate_remote_response($res)) { common_debug('ActivityPub Explorer: Found a valid remote actor for '.$url); @@ -408,4 +399,39 @@ class Activitypub_explorer return false; } + + /** + * Allows the Explorer to transverse a collection of persons. + * + * @author Diogo Cordeiro + * @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; + } }