diff --git a/ActivityPubPlugin.php b/ActivityPubPlugin.php index 2e48928..3882567 100755 --- a/ActivityPubPlugin.php +++ b/ActivityPubPlugin.php @@ -39,7 +39,11 @@ require_once __DIR__ . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR . "ex require_once __DIR__ . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR . "postman.php"; // So that this isn't hardcoded everywhere -define('ACTIVITYPUB_BASE_INSTANCE_URI', common_root_url()."index.php/user/"); +define('ACTIVITYPUB_BASE_INSTANCE_URI', common_root_url().'index.php/user/'); +const ACTIVITYPUB_PUBLIC_TO = ['https://www.w3.org/ns/activitystreams#Public', + 'Public', + 'as:Public' + ]; /** * @category Plugin @@ -81,32 +85,74 @@ class ActivityPubPlugin extends Plugin } /** - * Returns a notice from its URL since GNU Social doesn't provide - * this functionality + * Returns a notice from its URL. * * @author Diogo Cordeiro * @param string $url Notice's URL * @return Notice The Notice object * @throws Exception This function or provides a Notice or fails with exception */ - public static function get_local_notice_from_url($url) + public static function grab_notice_from_url($url) { + /* Offline Grabbing */ try { + // Look for a know remote notice return Notice::getByUri($url); } catch (Exception $e) { + // Look for a local notice (unfortunately GNU Social doesn't + // provide this functionality) try { $candidate = Notice::getByID(intval(substr($url, strlen(common_local_url('shownotice', ['notice' => '']))))); if ($candidate->getUrl() == $url) { // Sanity check return $candidate; } else { - common_debug ('ActivityPubPlugin Notice Grabber: '.$candidate->getUrl(). ' is different of '.$url); - throw new Exception('Notice not found.'); + common_debug('ActivityPubPlugin Notice Grabber: '.$candidate->getUrl(). ' is different of '.$url); } } catch (Exception $e) { - common_debug ('ActivityPubPlugin Notice Grabber failed to find: '.$url); - throw new Exception('Notice not found.'); + common_debug('ActivityPubPlugin Notice Grabber failed to find: '.$url. 'offline.'); } } + + /* Online Grabbing */ + $client = new HTTPClient(); + $headers = []; + $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(), JSON_UNESCAPED_SLASHES); + $settings = []; + try { + Activitypub_notice::validate_remote_notice($res); + } catch (Exception $e) { + common_debug('ActivityPub Explorer: Invalid potential remote notice while processing id: '.$url. '. He returned the following: '.json_encode($res, JSON_UNESCAPED_SLASHES)); + throw $e; + } + + if (isset($res->inReplyTo)) { + $settings['inReplyTo'] = $res->inReplyTo; + } + if (isset($res->latitude)) { + $settings['latitude'] = $res->latitude; + } + if (isset($res->longitude)) { + $settings['longitude'] = $res->longitude; + } + try { + return Activitypub_notice::create_notice( + ActivityPub_explorer::get_profile_from_url($res->atributtedTo), + $res->id, + $res->url, + $res->content, + $res->cc, + $settings + ); + } catch (Exception $e) { + common_debug('ActivityPubPlugin Notice Grabber failed to find: '.$url. 'online.'); + throw $e; + } + + // When all the above failed in its quest of grabbing the Notice + throw new Exception('Notice not found.'); } /** diff --git a/actions/apactorinbox.php b/actions/apactorinbox.php index 45634d0..315e7af 100755 --- a/actions/apactorinbox.php +++ b/actions/apactorinbox.php @@ -81,15 +81,12 @@ class apActorInboxAction extends ManagedAction ActivityPubReturn::error('Object was not specified.'); } - $discovery = new Activitypub_explorer; // Get valid Actor object try { - $actor_profile = $discovery->lookup($data->actor); - $actor_profile = $actor_profile[0]; + $actor_profile = ActivityPub_explorer::get_profile_from_url($data->actor); } catch (Exception $e) { - ActivityPubReturn::error('Invalid Actor.', 404); + ActivityPubReturn::error($e->getMessage(), 404); } - unset($discovery); // Public To: $public_to = ['https://www.w3.org/ns/activitystreams#Public', diff --git a/actions/apsharedinbox.php b/actions/apsharedinbox.php index 03ae6c4..27a58ae 100755 --- a/actions/apsharedinbox.php +++ b/actions/apsharedinbox.php @@ -71,15 +71,12 @@ class apSharedInboxAction extends ManagedAction ActivityPubReturn::error('Object was not specified.'); } - $discovery = new Activitypub_explorer; // Get valid Actor object try { - $actor_profile = $discovery->lookup($data->actor); - $actor_profile = $actor_profile[0]; + $actor_profile = ActivityPub_explorer::get_profile_from_url($data->actor); } catch (Exception $e) { - ActivityPubReturn::error('Invalid Actor.', 404); + ActivityPubReturn::error($e->getMessage(), 404); } - unset($discovery); // Public To: $public_to = ['https://www.w3.org/ns/activitystreams#Public', diff --git a/actions/inbox/Announce.php b/actions/inbox/Announce.php index 310c926..8c8d69a 100755 --- a/actions/inbox/Announce.php +++ b/actions/inbox/Announce.php @@ -31,7 +31,7 @@ if (!defined('GNUSOCIAL')) { try { try { - $object_notice = ActivityPubPlugin::get_local_notice_from_url($data->object); + $object_notice = ActivityPubPlugin::grab_notice_from_url($data->object); } catch (Exception $e) { ActivityPubReturn::error('Invalid Object specified.'); } diff --git a/actions/inbox/Create.php b/actions/inbox/Create.php index d3a5310..39c8b73 100755 --- a/actions/inbox/Create.php +++ b/actions/inbox/Create.php @@ -31,102 +31,38 @@ if (!defined('GNUSOCIAL')) { $valid_object_types = ['Note']; -// Validate data -if (!isset($data->object->id)) { - ActivityPubReturn::error('Object ID not specified.'); -} elseif (!filter_var($data->object->id, FILTER_VALIDATE_URL)) { - ActivityPubReturn::error('Invalid Object ID.'); -} -if (!(isset($data->object->type) && in_array($data->object->type, $valid_object_types))) { - ActivityPubReturn::error('Invalid Object type.'); -} -if (!isset($data->object->content)) { - ActivityPubReturn::error('Object content was not specified.'); -} -if (!isset($data->object->url)) { - ActivityPubReturn::error('Object url was not specified.'); -} elseif (!filter_var($data->object->url, FILTER_VALIDATE_URL)) { - ActivityPubReturn::error('Invalid Object URL.'); -} -if (!isset($data->object->to)) { - ActivityPubReturn::error('Object To was not specified.'); -} - -$content = $data->object->content; - -$act = new Activity(); -$act->verb = ActivityVerb::POST; -$act->time = time(); -$act->actor = $actor_profile->asActivityObject(); - -$act->context = new ActivityContext(); - -// Is this a reply? -if (isset($data->object->inReplyTo)) { - try { - $inReplyTo = ActivityPubPlugin::get_local_notice_from_url($data->object->inReplyTo); - } catch (Exception $e) { - ActivityPubReturn::error('Invalid Object inReplyTo value.'); - } - $act->context->replyToID = $inReplyTo->getUri(); - $act->context->replyToUrl = $inReplyTo->getUrl(); -} else { - $inReplyTo = null; -} - -$discovery = new Activitypub_explorer; - -// Generate Cc objects -if (isset($data->object->cc) && is_array($data->object->cc)) { - // Remove duplicates from Cc actors set - array_unique($data->object->cc); - foreach ($data->object->cc as $cc_url) { - try { - $to_profiles = array_merge($to_profiles, $discovery->lookup($cc_url)); - } catch (Exception $e) { - // Invalid actor found, just let it go. // TODO: Fallback to OStatus - } - } -} elseif (empty($data->object->cc) || in_array($data->object->cc, $public_to)) { - // No need to do anything else at this point, let's just break out the if -} else { - try { - $to_profiles = array_merge($to_profiles, $discovery->lookup($data->object->cc)); - } catch (Exception $e) { - // Invalid actor found, just let it go. // TODO: Fallback to OStatus - } -} - -unset($discovery); - -foreach ($to_profiles as $tp) { - $act->context->attention[ActivityPubPlugin::actor_uri($tp)] = 'http://activitystrea.ms/schema/1.0/person'; -} - -// Add location if that is set -if (isset($data->object->latitude, $data->object->longitude)) { - $act->context->location = Location::fromLatLon($data->object->latitude, $data->object->longitude); -} - -// Reject notice if it is too long (without the HTML) -if (Notice::contentTooLong($content)) { - ActivityPubReturn::error("That's too long. Maximum notice size is %d character."); -} - -$options = array('source' => 'ActivityPub', 'uri' => $data->object->id, 'url' => $data->object->url); -// $options gets filled with possible scoping settings -ToSelector::fillActivity($this, $act, $options); - -$actobj = new ActivityObject(); -$actobj->type = ActivityObject::NOTE; -$actobj->content = strip_tags($content,'