Merge branch 'dev' into 'actor_outbox'

Dev

See merge request dansup/ActivityPub!25
This commit is contained in:
Diogo Cordeiro 2018-08-07 03:36:23 +00:00
commit 5911b077ca
30 changed files with 398 additions and 217 deletions

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -30,7 +29,7 @@ if (!defined('GNUSOCIAL')) {
} }
// Ensure proper timezone // Ensure proper timezone
date_default_timezone_set('UTC'); date_default_timezone_set('GMT');
// Import required files by the plugin // Import required files by the plugin
require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
@ -106,8 +105,8 @@ class ActivityPubPlugin extends Plugin
// Look for a local notice (unfortunately GNU Social doesn't // Look for a local notice (unfortunately GNU Social doesn't
// provide this functionality natively) // provide this functionality natively)
try { try {
$candidate = Notice::getByID(intval(substr($url, strlen(common_local_url('shownotice', ['notice' => '']))))); $candidate = Notice::getByID(intval(substr($url, (strlen(common_local_url('apNotice', ['id' => 0]))-1))));
if ($candidate->getUrl() == $url) { // Sanity check if (common_local_url('apNotice', ['id' => $candidate->getID()]) === $url) { // Sanity check
return $candidate; return $candidate;
} else { } else {
common_debug('ActivityPubPlugin Notice Grabber: '.$candidate->getUrl(). ' is different of '.$url); common_debug('ActivityPubPlugin Notice Grabber: '.$candidate->getUrl(). ' is different of '.$url);
@ -151,49 +150,49 @@ class ActivityPubPlugin extends Plugin
['nickname' => Nickname::DISPLAY_FMT], ['nickname' => Nickname::DISPLAY_FMT],
'apActorProfile' 'apActorProfile'
); );
ActivityPubURLMapperOverwrite::variable(
$m,
'notice/:id',
['id' => '[0-9]+'],
'apNotice'
);
} }
// No .json here for convenience purposes on Notice grabber
$m->connect(
'note/:id',
['action' => 'apNotice'],
['id' => '[0-9]+']
);
$m->connect( $m->connect(
'user/:id/liked.json', 'user/:id/liked.json',
['action' => 'apActorLiked'], ['action' => 'apActorLiked'],
['id' => '[0-9]+'] ['id' => '[0-9]+']
); );
$m->connect( $m->connect(
'user/:id/followers.json', 'user/:id/followers.json',
['action' => 'apActorFollowers'], ['action' => 'apActorFollowers'],
['id' => '[0-9]+'] ['id' => '[0-9]+']
); );
$m->connect( $m->connect(
'user/:id/following.json', 'user/:id/following.json',
['action' => 'apActorFollowing'], ['action' => 'apActorFollowing'],
['id' => '[0-9]+'] ['id' => '[0-9]+']
); );
$m->connect( $m->connect(
'user/:id/inbox.json', 'user/:id/inbox.json',
['action' => 'apInbox'], ['action' => 'apInbox'],
['id' => '[0-9]+'] ['id' => '[0-9]+']
); );
$m->connect( $m->connect(
'user/:id/outbox.json', 'user/:id/outbox.json',
['action' => 'apActorOutbox'], ['action' => 'apActorOutbox'],
['id' => '[0-9]+'] ['id' => '[0-9]+']
); );
$m->connect( $m->connect(
'inbox.json', 'inbox.json',
['action' => 'apInbox'] ['action' => 'apInbox']
); );
} }
/** /**
@ -206,7 +205,7 @@ class ActivityPubPlugin extends Plugin
{ {
$versions[] = [ 'name' => 'ActivityPub', $versions[] = [ 'name' => 'ActivityPub',
'version' => GNUSOCIAL_VERSION, 'version' => GNUSOCIAL_VERSION,
'author' => 'Diogo Cordeiro, Daniel Supernault', 'author' => 'Diogo Cordeiro',
'homepage' => 'https://www.gnu.org/software/social/', 'homepage' => 'https://www.gnu.org/software/social/',
'rawdescription' => 'Adds ActivityPub Support']; 'rawdescription' => 'Adds ActivityPub Support'];
@ -214,8 +213,7 @@ class ActivityPubPlugin extends Plugin
} }
/** /**
* Dummy string on AccountProfileBlock stating that ActivityPub is active * Adds an indicator on Remote ActivityPub profiles.
* this is more of a placeholder for eventual useful stuff ._.
* *
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @return boolean hook return value * @return boolean hook return value
@ -226,8 +224,8 @@ class ActivityPubPlugin extends Plugin
return true; return true;
} }
try { try {
$aprofile = Activitypub_profile::getKV('profile_id', $profile->id); $aprofile = Activitypub_profile::from_profile($profile);
} catch (NoResultException $e) { } catch (Exception $e) {
// Not a remote ActivityPub_profile! Maybe some other network // Not a remote ActivityPub_profile! Maybe some other network
// that has imported a non-local user (e.g.: OStatus)? // that has imported a non-local user (e.g.: OStatus)?
return true; return true;
@ -278,7 +276,7 @@ class ActivityPubPlugin extends Plugin
} }
// Look for profile URLs, with or without scheme: // Look for profile URLs, with or without scheme:
$urls = array(); $urls = [];
if (preg_match('!^https?://((?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+(?:/\w+)+)$!', $arg)) { if (preg_match('!^https?://((?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+(?:/\w+)+)$!', $arg)) {
$urls[] = $arg; $urls[] = $arg;
} }
@ -336,7 +334,7 @@ class ActivityPubPlugin extends Plugin
*/ */
public static function extractUrlMentions($text, $preMention='@') public static function extractUrlMentions($text, $preMention='@')
{ {
$wmatches = array(); $wmatches = [];
// In the regexp below we need to match / _before_ URL_REGEX_VALID_PATH_CHARS because it otherwise gets merged // In the regexp below we need to match / _before_ URL_REGEX_VALID_PATH_CHARS because it otherwise gets merged
// with the TLD before (but / is in URL_REGEX_VALID_PATH_CHARS anyway, it's just its positioning that is important) // with the TLD before (but / is in URL_REGEX_VALID_PATH_CHARS anyway, it's just its positioning that is important)
$result = preg_match_all( $result = preg_match_all(
@ -386,7 +384,7 @@ class ActivityPubPlugin extends Plugin
*/ */
public function onEndFindMentions(Profile $sender, $text, &$mentions) public function onEndFindMentions(Profile $sender, $text, &$mentions)
{ {
$matches = array(); $matches = [];
foreach (self::extractWebfingerIds($text, '@') as $wmatch) { foreach (self::extractWebfingerIds($text, '@') as $wmatch) {
list($target, $pos) = $wmatch; list($target, $pos) = $wmatch;
@ -547,7 +545,7 @@ class ActivityPubPlugin extends Plugin
try { try {
$other = Activitypub_profile::from_profile($other); $other = Activitypub_profile::from_profile($other);
} catch (Exception $e) { } catch (Exception $e) {
return true; return true; // Let other plugin handle this instead
} }
$postman = new Activitypub_postman($profile, array($other)); $postman = new Activitypub_postman($profile, array($other));
@ -574,7 +572,7 @@ class ActivityPubPlugin extends Plugin
try { try {
$other = Activitypub_profile::from_profile($other); $other = Activitypub_profile::from_profile($other);
} catch (Exception $e) { } catch (Exception $e) {
return true; return true; // Let other plugin handle this instead
} }
$postman = new Activitypub_postman($profile, array($other)); $postman = new Activitypub_postman($profile, array($other));
@ -585,7 +583,7 @@ class ActivityPubPlugin extends Plugin
} }
/** /**
* Notify remote users when their notices get favorited. * Notify remote users when their notices get favourited.
* *
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @param Profile $profile of local user doing the faving * @param Profile $profile of local user doing the faving
@ -600,7 +598,7 @@ class ActivityPubPlugin extends Plugin
return true; return true;
} }
$other = array(); $other = [];
try { try {
$other[] = Activitypub_profile::from_profile($notice->getProfile()); $other[] = Activitypub_profile::from_profile($notice->getProfile());
} catch (Exception $e) { } catch (Exception $e) {
@ -644,7 +642,7 @@ class ActivityPubPlugin extends Plugin
} }
/** /**
* Notify remote users when their notices get de-favorited. * Notify remote users when their notices get de-favourited.
* *
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @param Profile $profile of local user doing the de-faving * @param Profile $profile of local user doing the de-faving
@ -659,7 +657,7 @@ class ActivityPubPlugin extends Plugin
return true; return true;
} }
$other = array(); $other = [];
try { try {
$other[] = Activitypub_profile::from_profile($notice->getProfile()); $other[] = Activitypub_profile::from_profile($notice->getProfile());
} catch (Exception $e) { } catch (Exception $e) {
@ -718,7 +716,7 @@ class ActivityPubPlugin extends Plugin
return true; return true;
} }
$other = array(); $other = [];
foreach ($notice->getAttentionProfiles() as $to_profile) { foreach ($notice->getAttentionProfiles() as $to_profile) {
try { try {
@ -765,44 +763,12 @@ class ActivityPubPlugin extends Plugin
{ {
assert($notice->id > 0); // Ignore if not a valid notice assert($notice->id > 0); // Ignore if not a valid notice
$profile = Profile::getKV($notice->profile_id); $profile = $notice->getProfile();
if (!$profile->isLocal()) { if (!$profile->isLocal()) {
return true; return true;
} }
$other = array();
try {
$other[] = Activitypub_profile::from_profile($notice->getProfile());
} catch (Exception $e) {
// Local user can be ignored
}
foreach ($notice->getAttentionProfiles() as $to_profile) {
try {
$other[] = Activitypub_profile::from_profile($to_profile);
} catch (Exception $e) {
// Local user can be ignored
}
}
// Is Announce
if ($notice->isRepeat()) {
$repeated_notice = Notice::getKV('id', $notice->repeat_of);
if ($repeated_notice instanceof Notice) {
try {
$other[] = Activitypub_profile::from_profile($repeated_notice->getProfile());
} catch (Exception $e) {
// Local user can be ignored
}
$postman = new Activitypub_postman($profile, $other);
// That was it
$postman->announce($repeated_notice);
return true;
}
}
// Ignore for activity/non-post-verb notices // Ignore for activity/non-post-verb notices
if (method_exists('ActivityUtils', 'compareVerbs')) { if (method_exists('ActivityUtils', 'compareVerbs')) {
$is_post_verb = ActivityUtils::compareVerbs( $is_post_verb = ActivityUtils::compareVerbs(
@ -816,7 +782,16 @@ class ActivityPubPlugin extends Plugin
return true; return true;
} }
// Create $other = [];
foreach ($notice->getAttentionProfiles() as $mention) {
try {
$other[] = Activitypub_profile::from_profile($mention);
} catch (Exception $e) {
// Local user can be ignored
}
}
// Is a reply?
if ($notice->reply_to) { if ($notice->reply_to) {
try { try {
$other[] = Activitypub_profile::from_profile($notice->getParent()->getProfile()); $other[] = Activitypub_profile::from_profile($notice->getParent()->getProfile());
@ -824,10 +799,9 @@ class ActivityPubPlugin extends Plugin
// Local user can be ignored // Local user can be ignored
} }
try { try {
$mentions = $notice->getParent()->getAttentionProfiles(); foreach ($notice->getParent()->getAttentionProfiles() as $mention) {
foreach ($mentions as $to_profile) {
try { try {
$other[] = Activitypub_profile::from_profile($to_profile); $other[] = Activitypub_profile::from_profile($mention);
} catch (Exception $e) { } catch (Exception $e) {
// Local user can be ignored // Local user can be ignored
} }
@ -839,10 +813,27 @@ class ActivityPubPlugin extends Plugin
common_log(LOG_ERR, "Parent notice's author not found: ".$e->getMessage()); common_log(LOG_ERR, "Parent notice's author not found: ".$e->getMessage());
} }
} }
$postman = new Activitypub_postman($profile, $other);
// Is an Announce?
if ($notice->isRepeat()) {
$repeated_notice = Notice::getKV('id', $notice->repeat_of);
if ($repeated_notice instanceof Notice) {
try {
$other[] = Activitypub_profile::from_profile($repeated_notice->getProfile());
} catch (Exception $e) {
// Local user can be ignored
}
// That was it
$postman = new Activitypub_postman($profile, $other);
$postman->announce($repeated_notice);
return true;
}
}
// That was it // That was it
$postman->create($notice); $postman = new Activitypub_postman($profile, $other);
$postman->create_note($notice);
return true; return true;
} }

View File

@ -40,10 +40,14 @@ We use [SemVer](http://semver.org/) for versioning. For the versions available,
## Credits ## Credits
* **[Diogo Cordeiro](https://www.diogo.site/)** * **[Diogo Cordeiro](https://www.diogo.site/)**
* **[Daniel Supernault](https://github.com/dansup)**
See also the list of [contributors](https://git.gnu.io/gnu/GS-ActivityPub-Plugin/contributors) who participated in this project. See also the list of [contributors](https://git.gnu.io/gnu/GS-ActivityPub-Plugin/contributors) who participated in this project.
## Extra special thanks
* **[Daniel Supernault](https://github.com/dansup)**
* **[Mikael Nordfeldth](https://mmn-o.se/)**
## License ## License
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -108,7 +107,7 @@ class apActorFollowersAction extends ManagedAction
} }
/** /**
* Generates a list of followers for a given profile. * Generates a list of stalkers for a given profile.
* *
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @param Profile $profile * @param Profile $profile
@ -116,7 +115,7 @@ class apActorFollowersAction extends ManagedAction
* @param int32 $limit * @param int32 $limit
* @return Array of URIs * @return Array of URIs
*/ */
public function generate_followers($profile, $since, $limit) public static function generate_followers($profile, $since, $limit)
{ {
/* Fetch Followers */ /* Fetch Followers */
try { try {
@ -130,6 +129,7 @@ class apActorFollowersAction extends ManagedAction
while ($sub->fetch()) { while ($sub->fetch()) {
$subs[] = ActivityPubPlugin::actor_uri($sub); $subs[] = ActivityPubPlugin::actor_uri($sub);
} }
return $subs; return $subs;
} }
} }

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -108,7 +107,7 @@ class apActorFollowingAction extends ManagedAction
} }
/** /**
* Generates a list of people following given profile. * Generates the list of those a given profile is stalking.
* *
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @param Profile $profile * @param Profile $profile

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -124,7 +123,7 @@ class apActorOutboxAction extends ManagedAction
// TODO: Handle other types // TODO: Handle other types
if ($note->object_type == 'http://activitystrea.ms/schema/1.0/note') { if ($note->object_type == 'http://activitystrea.ms/schema/1.0/note') {
$notices[] = Activitypub_create::create_to_array( $notices[] = Activitypub_create::create_to_array(
ActivityPubPlugin::actor_uri($note->getProfile()), ActivityPubPlugin::actor_uri($note->getProfile()),
Activitypub_notice::notice_to_array($note) Activitypub_notice::notice_to_array($note)
); );
} }

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -55,16 +54,50 @@ class apInboxAction extends ManagedAction
ActivityPubReturn::error('Only POST requests allowed.'); ActivityPubReturn::error('Only POST requests allowed.');
} }
common_debug('ActivityPub Shared Inbox: Received a POST request.'); common_debug('ActivityPub Inbox: Received a POST request.');
$data = file_get_contents('php://input'); $data = file_get_contents('php://input');
common_debug('ActivityPub Shared Inbox: Request contents: '.$data); common_debug('ActivityPub Inbox: Request contents: '.$data);
$data = json_decode(file_get_contents('php://input'), true); $data = json_decode(file_get_contents('php://input'), true);
if (!isset($data['actor'])) {
ActivityPubReturn::error('Actor not found in the request.');
}
$actor = ActivityPub_explorer::get_profile_from_url($data['actor']);
$actor_public_key = new Activitypub_rsa();
$actor_public_key = $actor_public_key->ensure_public_key($actor);
common_debug('ActivityPub Inbox: HTTP Signature: Validation will now start!');
$headers = $this->get_all_headers();
common_debug('ActivityPub Inbox: Request Headers: '.print_r($headers, true));
// TODO: Validate HTTP Signature, if it fails, attempt once with profile update
common_debug('ActivityPub Inbox: HTTP Signature: Authorized request. Will now start the inbox handler.');
try { try {
new Activitypub_inbox_handler($data); new Activitypub_inbox_handler($data, $actor);
ActivityPubReturn::answer(); ActivityPubReturn::answer();
} catch (Exception $e) { } catch (Exception $e) {
ActivityPubReturn::error($e->getMessage()); ActivityPubReturn::error($e->getMessage());
} }
} }
/**
* Get all HTTP header key/values as an associative array for the current request.
*
* @author PHP Manual Contributed Notes <joyview@gmail.com>
* @return string[string] The HTTP header key/value pairs.
*/
private function get_all_headers()
{
$headers = [];
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$headers[strtolower(str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))))] = $value;
}
}
return $headers;
}
} }

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -50,10 +49,7 @@ class Activitypub_accept extends Managed_DataObject
public static function accept_to_array($object) public static function accept_to_array($object)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'id' => common_root_url().'accept_follow_from_'.urlencode($object['actor']).'_to_'.urlencode($object['object']), 'id' => common_root_url().'accept_follow_from_'.urlencode($object['actor']).'_to_'.urlencode($object['object']),
'type' => 'Accept', 'type' => 'Accept',
'actor' => $object['object'], 'actor' => $object['object'],

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -50,10 +49,7 @@ class Activitypub_announce extends Managed_DataObject
public static function announce_to_array($actor, $object) public static function announce_to_array($actor, $object)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
"type" => "Announce", "type" => "Announce",
"actor" => $actor, "actor" => $actor,
"object" => $object "object" => $object

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -50,10 +49,7 @@ class Activitypub_attachment extends Managed_DataObject
public static function attachment_to_array($attachment) public static function attachment_to_array($attachment)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type' => 'Document', 'type' => 'Document',
'mediaType' => $attachment->mimetype, 'mediaType' => $attachment->mimetype,
'url' => $attachment->getUrl(), 'url' => $attachment->getUrl(),

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -51,10 +50,7 @@ class Activitypub_create extends Managed_DataObject
public static function create_to_array($actor, $object) public static function create_to_array($actor, $object)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'id' => $object['id'].'/create', 'id' => $object['id'].'/create',
'type' => 'Create', 'type' => 'Create',
'to' => $object['to'], 'to' => $object['to'],

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -50,10 +49,7 @@ class Activitypub_delete extends Managed_DataObject
public static function delete_to_array($actor, $object) public static function delete_to_array($actor, $object)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'id' => $object.'/delete', 'id' => $object.'/delete',
'type' => 'Delete', 'type' => 'Delete',
'actor' => $actor, 'actor' => $actor,

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -51,10 +50,7 @@ class Activitypub_follow extends Managed_DataObject
public static function follow_to_array($actor, $object) public static function follow_to_array($actor, $object)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'id' => common_root_url().'follow_from_'.urlencode($actor).'_to_'.urlencode($object), 'id' => common_root_url().'follow_from_'.urlencode($actor).'_to_'.urlencode($object),
'type' => 'Follow', 'type' => 'Follow',
'actor' => $actor, 'actor' => $actor,

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -51,10 +50,7 @@ class Activitypub_like extends Managed_DataObject
public static function like_to_array($actor, $object) public static function like_to_array($actor, $object)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'id' => common_root_url().'like_from_'.urlencode($actor).'_to_'.urlencode($object), 'id' => common_root_url().'like_from_'.urlencode($actor).'_to_'.urlencode($object),
"type" => "Like", "type" => "Like",
"actor" => $actor, "actor" => $actor,

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -51,10 +50,7 @@ class Activitypub_mention_tag extends Managed_DataObject
public static function mention_tag_to_array_from_values($href, $name) public static function mention_tag_to_array_from_values($href, $name)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
"type" => "Mention", "type" => "Mention",
"href" => $href, "href" => $href,
"name" => $name "name" => $name

View File

@ -19,7 +19,6 @@
* *
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Daniel Supernault <danielsupernault@gmail.com>
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
@ -72,11 +71,8 @@ class Activitypub_notice extends Managed_DataObject
$to[]= 'https://www.w3.org/ns/activitystreams#Public'; $to[]= 'https://www.w3.org/ns/activitystreams#Public';
$item = [ $item = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams', 'id' => common_local_url('apNotice', ['id' => $notice->getID()]),
'https://w3id.org/security/v1'
],
'id' => $notice->getUrl(),
'type' => 'Note', 'type' => 'Note',
'published' => str_replace(' ', 'T', $notice->getCreated()).'Z', 'published' => str_replace(' ', 'T', $notice->getCreated()).'Z',
'url' => $notice->getUrl(), 'url' => $notice->getUrl(),
@ -93,7 +89,7 @@ class Activitypub_notice extends Managed_DataObject
// Is this a reply? // Is this a reply?
if (!empty($notice->reply_to)) { if (!empty($notice->reply_to)) {
$item['inReplyTo'] = Notice::getById($notice->reply_to)->getUrl(); $item['inReplyTo'] = common_local_url('apNotice', ['id' => $notice->getID()]);
$item['inReplyToAtomUri'] = Notice::getById($notice->reply_to)->getUrl(); $item['inReplyToAtomUri'] = Notice::getById($notice->reply_to)->getUrl();
} }
@ -124,7 +120,6 @@ class Activitypub_notice extends Managed_DataObject
$id = $object['id']; // int32 $id = $object['id']; // int32
$url = $object['url']; // string $url = $object['url']; // string
$content = $object['content']; // string $content = $object['content']; // string
$cc = $object['cc']; // array|string
// possible keys: ['inReplyTo', 'latitude', 'longitude', 'attachment'] // possible keys: ['inReplyTo', 'latitude', 'longitude', 'attachment']
$settings = []; $settings = [];
@ -192,43 +187,41 @@ class Activitypub_notice extends Managed_DataObject
if (isset($settings['inReplyTo'])) { if (isset($settings['inReplyTo'])) {
try { try {
$inReplyTo = ActivityPubPlugin::grab_notice_from_url($settings['inReplyTo']); $inReplyTo = ActivityPubPlugin::grab_notice_from_url($settings['inReplyTo']);
$act->context->replyToID = $inReplyTo->getUri();
$act->context->replyToUrl = $inReplyTo->getUrl();
} catch (Exception $e) { } catch (Exception $e) {
throw new Exception('Invalid Object inReplyTo value: '.$e->getMessage()); // It failed to grab, maybe we got this note from another source
// (e.g.: OStatus) that handles this differently or we really
// failed to get it...
// Welp, nothing that we can do about, let's
// just fake we don't have such notice.
} }
$act->context->replyToID = $inReplyTo->getUri();
$act->context->replyToUrl = $inReplyTo->getUrl();
} else { } else {
$inReplyTo = null; $inReplyTo = null;
} }
$discovery = new Activitypub_explorer; // Mentions
$mentions = [];
// Generate Cc objects if (isset($object['tag']) && is_array($object['tag'])) {
$cc_profiles = []; foreach ($object['tag'] as $tag) {
if (is_array($cc)) { if ($tag['type'] == 'Mention') {
// Remove duplicates from Cc actors set $mentions[] = $tag['href'];
array_unique($cc);
foreach ($cc as $cc_url) {
try {
$cc_profiles = array_merge($cc_profiles, $discovery->lookup($cc_url));
} catch (Exception $e) {
// Invalid actor found, just let it go. // TODO: Fallback to OStatus
} }
} }
} elseif (empty($cc) || in_array($cc, ACTIVITYPUB_PUBLIC_TO)) { }
// No need to do anything else at this point, let's just break out the if $mentions_profiles = [];
} else { $discovery = new Activitypub_explorer;
foreach ($mentions as $mention) {
try { try {
$cc_profiles = $discovery->lookup($cc); $mentions_profiles[] = $discovery->lookup($mention)[0];
} catch (Exception $e) { } catch (Exception $e) {
// Invalid actor found, just let it go. // TODO: Fallback to OStatus // Invalid actor found, just let it go. // TODO: Fallback to OStatus
} }
} }
unset($discovery); unset($discovery);
foreach ($cc_profiles as $cp) { foreach ($mentions_profiles as $mp) {
$act->context->attention[ActivityPubPlugin::actor_uri($cp)] = 'http://activitystrea.ms/schema/1.0/person'; $act->context->attention[ActivityPubPlugin::actor_uri($mp)] = 'http://activitystrea.ms/schema/1.0/person';
} }
// Add location if that is set // Add location if that is set

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -96,10 +95,7 @@ class Activitypub_profile extends Managed_DataObject
$public_key = $rsa->ensure_public_key($profile); $public_key = $rsa->ensure_public_key($profile);
unset($rsa); unset($rsa);
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1"
],
'id' => $uri, 'id' => $uri,
'type' => 'Person', 'type' => 'Person',
'following' => common_local_url('apActorFollowing', ['id' => $id]), 'following' => common_local_url('apActorFollowing', ['id' => $id]),
@ -242,9 +238,13 @@ class Activitypub_profile extends Managed_DataObject
*/ */
private static function create_from_local_profile(Profile $profile) private static function create_from_local_profile(Profile $profile)
{ {
$url = $profile->getURL(); $url = $profile->getUri();
$inboxes = Activitypub_explorer::get_actor_inboxes_uri($url); $inboxes = Activitypub_explorer::get_actor_inboxes_uri($url);
if ($inboxes == null) {
throw new Exception('This is not an ActivityPub user thus AProfile is politely refusing to proceed.');
}
$aprofile->created = $aprofile->modified = common_sql_now(); $aprofile->created = $aprofile->modified = common_sql_now();
$aprofile = new Activitypub_profile; $aprofile = new Activitypub_profile;
@ -413,4 +413,57 @@ class Activitypub_profile extends Managed_DataObject
// TRANS: Exception. %s is a webfinger address. // TRANS: Exception. %s is a webfinger address.
throw new Exception(sprintf(_m('Could not find a valid profile for "%s".'), $addr)); throw new Exception(sprintf(_m('Could not find a valid profile for "%s".'), $addr));
} }
/**
* Update remote user profile in local instance
* Depends on do_update
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @param array $res remote response
* @return Profile remote Profile object
*/
public static function update_profile($aprofile, $res)
{
// ActivityPub Profile
$aprofile->uri = $res['id'];
$aprofile->nickname = $res['preferredUsername'];
$aprofile->fullname = isset($res['name']) ? $res['name'] : null;
$aprofile->bio = isset($res['summary']) ? substr(strip_tags($res['summary']), 0, 1000) : null;
$aprofile->inboxuri = $res['inbox'];
$aprofile->sharedInboxuri = isset($res['endpoints']['sharedInbox']) ? $res['endpoints']['sharedInbox'] : $res['inbox'];
$profile = $aprofile->local_profile();
$profile->modified = $aprofile->modified = common_sql_now();
$fields = [
'uri' => 'profileurl',
'nickname' => 'nickname',
'fullname' => 'fullname',
'bio' => 'bio'
];
foreach ($fields as $af => $pf) {
$profile->$pf = $aprofile->$af;
}
// Profile
$profile->update();
$aprofile->update();
// Public Key
Activitypub_rsa::update_public_key($profile, $res['publicKey']['publicKeyPem']);
// Avatar
if (isset($res['icon']['url'])) {
try {
Activitypub_explorer::update_avatar($profile, $res['icon']['url']);
} catch (Exception $e) {
// Let the exception go, it isn't a serious issue
common_debug('An error ocurred while grabbing remote avatar'.$e->getMessage());
}
}
return $profile;
}
} }

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -50,10 +49,7 @@ class Activitypub_reject extends Managed_DataObject
public static function reject_to_array($object) public static function reject_to_array($object)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
"type" => "Reject", "type" => "Reject",
"object" => $object "object" => $object
]; ];

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -84,16 +83,15 @@ class Activitypub_rsa extends Managed_DataObject
return $apRSA->private_key; return $apRSA->private_key;
} }
/** /**
* Guarantees a Public Key for a given profile. * Guarantees a Public Key for a given profile.
* *
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @param Profile $profile * @param Profile $profile
* @return string The public key * @return string The public key
* @throws Exception It should never occur * @throws ServerException It should never occur, but if so, we break everything!
*/ */
public function ensure_public_key($profile) public function ensure_public_key($profile, $fetch = true)
{ {
$this->profile_id = $profile->getID(); $this->profile_id = $profile->getID();
$apRSA = self::getKV('profile_id', $this->profile_id); $apRSA = self::getKV('profile_id', $this->profile_id);
@ -103,7 +101,14 @@ class Activitypub_rsa extends Managed_DataObject
self::generate_keys($this->private_key, $this->public_key); self::generate_keys($this->private_key, $this->public_key);
$this->store_keys(); $this->store_keys();
} else { } else {
throw new Exception('No Keys for this Profile. That\'s odd.'); // This should never happen, but try to recover!
if ($fetch) {
$res = Activitypub_explorer::get_remote_user_activity(ActivityPubPlugin::actor_uri($profile));
Activitypub_rsa::update_public_key($profile, $res['publicKey']['publicKeyPem']);
return ensure_public_key($profile, false);
} else {
throw new ServerException('Activitypub_rsa: Failed to find keys for given profile. That should have not happened!');
}
} }
} }
return $apRSA->public_key; return $apRSA->public_key;
@ -121,7 +126,6 @@ class Activitypub_rsa extends Managed_DataObject
$this->created = $this->modified = common_sql_now(); $this->created = $this->modified = common_sql_now();
$ok = $this->insert(); $ok = $this->insert();
if ($ok === false) { if ($ok === false) {
$profile->query('ROLLBACK');
throw new ServerException('Cannot save ActivityPub RSA.'); throw new ServerException('Cannot save ActivityPub RSA.');
} }
} }
@ -152,4 +156,23 @@ class Activitypub_rsa extends Managed_DataObject
$public_key = $pubKey["key"]; $public_key = $pubKey["key"];
unset($pubKey); unset($pubKey);
} }
/**
* Update public key.
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @param Profile $profile
* @param string $public_key
*/
public static function update_public_key($profile, $public_key)
{
// Public Key
$apRSA = new Activitypub_rsa();
$apRSA->profile_id = $profile->getID();
$apRSA->public_key = $public_key;
$apRSA->modified = common_sql_now();
if(!$apRSA->update()) {
$apRSA->insert();
}
}
} }

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -50,10 +49,7 @@ class Activitypub_tag extends Managed_DataObject
public static function tag_to_array($tag) public static function tag_to_array($tag)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'name' => $tag, 'name' => $tag,
'url' => common_local_url('tag', ['tag' => $tag]) 'url' => common_local_url('tag', ['tag' => $tag])
]; ];

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -50,10 +49,7 @@ class Activitypub_undo extends Managed_DataObject
public static function undo_to_array($object) public static function undo_to_array($object)
{ {
$res = [ $res = [
'@context' => [ '@context' => 'https://www.w3.org/ns/activitystreams',
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'id' => $object['id'].'/undo', 'id' => $object['id'].'/undo',
'type' => 'Undo', 'type' => 'Undo',
'actor' => $object['actor'], 'actor' => $object['actor'],

View File

@ -0,0 +1,104 @@
#!/usr/bin/env php
<?php
/**
* GNU social - a federating social network
*
* ActivityPubPlugin implementation for GNU Social
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
* @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/
*/
define('INSTALLDIR', realpath(__DIR__ . '/../../..'));
$shortoptions = 'u:af';
$longoptions = ['uri=', 'all', 'force'];
$helptext = <<<END_OF_HELP
update_activitypub_profiles.php [options]
Refetch / update ActivityPub RSA keys, profile info and avatars. Useful if you
do something like accidentally delete your avatars directory when
you have no backup.
-u --uri ActivityPub profile URI to update
-a --all update all
END_OF_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
$quiet = have_option('q', 'quiet');
if (!$quiet) {
echo "ActivityPub Profiles updater will now start!\n";
echo "Summoning Diogo Cordeiro, Richard Stallman and Chuck Norris to help us with this task!\n";
}
if (have_option('u', 'uri')) {
$uri = get_option_value('u', 'uri');
$discovery = new Activitypub_explorer();
$discovery = $discovery->lookup($uri);
if (empty($discovery)) {
echo "Bad URI\n";
exit(1);
}
$user = $discovery->lookup($uri)[0];
try {
$res = Activitypub_explorer::get_remote_user_activity($uri);
} catch (Exception $e) {
echo $e->getMessage()."\n";
exit(1);
}
if (!$quiet) {
echo "Updated ".Activitypub_profile::update_profile($user, $res)->getBestName()."\n";
}
} else if (!have_option('a', 'all')) {
show_help();
exit(1);
}
$user = new Activitypub_profile();
$cnt = $user->find();
if (!empty($cnt)) {
if (!$quiet) {
echo "Found {$cnt} ActivityPub profiles:\n";
}
} else {
if (have_option('u', 'uri')) {
if (!$quiet) {
echo "Couldn't find an existing ActivityPub profile with that URI.\n";
}
} else {
if (!$quiet) {
echo "Couldn't find any existing ActivityPub profiles.\n";
}
}
exit(0);
}
while ($user->fetch()) {
try {
$res = Activitypub_explorer::get_remote_user_activity($user->uri);
if (!$quiet) {
echo "Updated ".Activitypub_profile::update_profile($user, $res)->getBestName()."\n";
}
} catch (Exception $e) {
// let it go
}
}

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -204,7 +203,7 @@ class Activitypub_explorer
common_debug('ActivityPub Explorer: Trying to grab a remote actor for '.$url); common_debug('ActivityPub Explorer: Trying to grab a remote actor for '.$url);
if (!isset($this->temp_res)) { if (!isset($this->temp_res)) {
$client = new HTTPClient(); $client = new HTTPClient();
$headers = array(); $headers = [];
$headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; $headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
$headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social'; $headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
$response = $client->get($url, $headers); $response = $client->get($url, $headers);
@ -259,10 +258,10 @@ class Activitypub_explorer
// Avatar // Avatar
if (isset($res['icon']['url'])) { if (isset($res['icon']['url'])) {
try { try {
$this->_store_avatar($profile, $res['icon']['url']); $this->update_avatar($profile, $res['icon']['url']);
} catch (Exception $e) { } catch (Exception $e) {
// Let the exception go, it isn't a serious issue // Let the exception go, it isn't a serious issue
common_debug('An error ocurred while grabbing remote avatar'.$e->getMessage()); common_debug('ActivityPub Explorer: An error ocurred while grabbing remote avatar: '.$e->getMessage());
} }
} }
@ -278,7 +277,7 @@ class Activitypub_explorer
* @return Avatar The Avatar we have on disk. * @return Avatar The Avatar we have on disk.
* @throws Exception in various failure cases * @throws Exception in various failure cases
*/ */
private function _store_avatar(Profile $profile, $url) public static function update_avatar(Profile $profile, $url)
{ {
common_debug('ActivityPub Explorer: Started grabbing remote avatar from: '.$url); common_debug('ActivityPub Explorer: Started grabbing remote avatar from: '.$url);
if (!filter_var($url, FILTER_VALIDATE_URL)) { if (!filter_var($url, FILTER_VALIDATE_URL)) {
@ -388,7 +387,7 @@ class Activitypub_explorer
public static function get_actor_inboxes_uri($url) public static function get_actor_inboxes_uri($url)
{ {
$client = new HTTPClient(); $client = new HTTPClient();
$headers = array(); $headers = [];
$headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; $headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
$headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social'; $headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
$response = $client->get($url, $headers); $response = $client->get($url, $headers);
@ -416,7 +415,7 @@ class Activitypub_explorer
private function travel_collection($url) private function travel_collection($url)
{ {
$client = new HTTPClient(); $client = new HTTPClient();
$headers = array(); $headers = [];
$headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; $headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
$headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social'; $headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
$response = $client->get($url, $headers); $response = $client->get($url, $headers);
@ -439,4 +438,27 @@ class Activitypub_explorer
return true; return true;
} }
/**
* Get a remote user array from its URL (this function is only used for
* profile updating and shall not be used for anything else)
*
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @param string $url User's url
* @throws Exception
*/
public static function get_remote_user_activity($url)
{
$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(), true);
if (Activitypub_explorer::validate_remote_response($res)) {
common_debug('ActivityPub Explorer: Found a valid remote actor for '.$url);
return $res;
}
throw new Exception('ActivityPub Explorer: Failed to get activity.');
}
} }

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -49,8 +48,9 @@ class Activitypub_inbox_handler
* *
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @param Array $activity Activity we are receiving * @param Array $activity Activity we are receiving
* @param Profile $actor_profile Actor originating the activity
*/ */
public function __construct($activity) public function __construct($activity, $actor_profile = null)
{ {
$this->activity = $activity; $this->activity = $activity;
$this->object = $activity['object']; $this->object = $activity['object'];
@ -59,7 +59,11 @@ class Activitypub_inbox_handler
$this->validate_activity(); $this->validate_activity();
// Get Actor's Profile // Get Actor's Profile
$this->actor = ActivityPub_explorer::get_profile_from_url($this->activity['actor']); if (!is_null($actor_profile)) {
$this->actor = $actor_profile;
} else {
$this->actor = ActivityPub_explorer::get_profile_from_url($this->activity['actor']);
}
// Handle the Activity // Handle the Activity
$this->process(); $this->process();
@ -98,7 +102,7 @@ class Activitypub_inbox_handler
case 'Like': case 'Like':
case 'Announce': case 'Announce':
if (!filter_var($this->object, FILTER_VALIDATE_URL)) { if (!filter_var($this->object, FILTER_VALIDATE_URL)) {
throw new Exception("Object is not a valid Object URI for Activity."); throw new Exception('Object is not a valid Object URI for Activity.');
} }
break; break;
case 'Undo': case 'Undo':

View File

@ -20,7 +20,6 @@
* @category Plugin * @category Plugin
* @package GNUsocial * @package GNUsocial
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @author Daniel Supernault <danielsupernault@gmail.com>
* @copyright 2018 Free Software Foundation http://fsf.org * @copyright 2018 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.gnu.org/software/social/ * @link https://www.gnu.org/software/social/
@ -60,27 +59,37 @@ class Activitypub_postman
* @param Profile $from Profile of sender * @param Profile $from Profile of sender
* @param Array of Activitypub_profile $to destinataries * @param Array of Activitypub_profile $to destinataries
*/ */
public function __construct($from, $to = []) public function __construct($from, $to)
{ {
$this->actor = $from; $this->actor = $from;
$discovery = new Activitypub_explorer();
$this->to = $to; $this->to = $to;
$followers = apActorFollowersAction::generate_followers($this->actor, 0, null);
foreach ($followers as $sub) {
try {
$to[]= Activitypub_profile::from_profile($discovery->lookup($sub)[0]);
} catch (Exception $e) {
// Not an ActivityPub Remote Follower, let it go
}
}
unset($discovery);
$this->actor_uri = ActivityPubPlugin::actor_uri($this->actor); $this->actor_uri = ActivityPubPlugin::actor_uri($this->actor);
$actor_private_key = new Activitypub_rsa(); $actor_private_key = new Activitypub_rsa();
$actor_private_key = $actor_private_key->get_private_key($this->actor); $actor_private_key = $actor_private_key->get_private_key($this->actor);
$context = new Context([ $context = new Context([
'keys' => [$this->actor_uri."#public-key" => $actor_private_key], 'keys' => [$this->actor_uri.'#public-key' => $actor_private_key],
'algorithm' => 'rsa-sha256', 'algorithm' => 'rsa-sha256',
'headers' => ['(request-target)', 'date', 'content-type', 'accept', 'user-agent'], 'headers' => ['(request-target)', 'date', 'content-type', 'accept', 'user-agent'],
]); ]);
$this->to = $to;
$this->headers = [ $this->headers = [
'content-type' => 'application/activity+json', 'content-type' => 'application/activity+json',
'accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', 'accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'user-agent' => 'GNUSocialBot v0.1 - https://gnu.io/social', 'user-agent' => 'GNUSocialBot v0.1 - https://gnu.io/social',
'date' => date('D, d M Y h:i:s') . ' GMT' 'date' => gmdate('D, d M Y H:i:s \G\M\T', time())
]; ];
$handlerStack = GuzzleHttpSignatures::defaultHandlerFromContext($context); $handlerStack = GuzzleHttpSignatures::defaultHandlerFromContext($context);
@ -228,15 +237,12 @@ class Activitypub_postman
* @author Diogo Cordeiro <diogo@fc.up.pt> * @author Diogo Cordeiro <diogo@fc.up.pt>
* @param Notice $notice * @param Notice $notice
*/ */
public function create($notice) public function create_note($notice)
{ {
$data = Activitypub_create::create_to_array( $data = Activitypub_create::create_to_array(
$this->actor_uri, $this->actor_uri,
Activitypub_notice::notice_to_array($notice) Activitypub_notice::notice_to_array($notice)
); );
if (isset($notice->reply_to)) {
$data["object"]["reply_to"] = $notice->getParent()->getUrl();
}
$data = json_encode($data, JSON_UNESCAPED_SLASHES); $data = json_encode($data, JSON_UNESCAPED_SLASHES);
foreach ($this->to_inbox() as $inbox) { foreach ($this->to_inbox() as $inbox) {