Inbox Reinvented
This commit is contained in:
parent
de432cda88
commit
43ebdfa727
@ -38,6 +38,7 @@ require_once __DIR__ . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'd
|
|||||||
require_once __DIR__ . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'AcceptHeader.php';
|
require_once __DIR__ . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'AcceptHeader.php';
|
||||||
require_once __DIR__ . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'explorer.php';
|
require_once __DIR__ . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'explorer.php';
|
||||||
require_once __DIR__ . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'postman.php';
|
require_once __DIR__ . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'postman.php';
|
||||||
|
require_once __DIR__ . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'inbox_handler.php';
|
||||||
|
|
||||||
// So that this isn't hardcoded everywhere
|
// So that this isn't hardcoded everywhere
|
||||||
define('ACTIVITYPUB_BASE_ACTOR_URI', common_root_url().'index.php/user/');
|
define('ACTIVITYPUB_BASE_ACTOR_URI', common_root_url().'index.php/user/');
|
||||||
@ -122,40 +123,9 @@ class ActivityPubPlugin extends Plugin
|
|||||||
$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);
|
||||||
$res = json_decode($response->getBody(), true);
|
$object = json_decode($response->getBody(), true);
|
||||||
$settings = [];
|
Activitypub_notice::validate_note($object);
|
||||||
try {
|
return Activitypub_notice::create_notice($object);
|
||||||
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 $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['attributedTo']),
|
|
||||||
$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.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,13 +180,13 @@ class ActivityPubPlugin extends Plugin
|
|||||||
|
|
||||||
$m->connect(
|
$m->connect(
|
||||||
'user/:id/inbox.json',
|
'user/:id/inbox.json',
|
||||||
['action' => 'apActorInbox'],
|
['action' => 'apInbox'],
|
||||||
['id' => '[0-9]+']
|
['id' => '[0-9]+']
|
||||||
);
|
);
|
||||||
|
|
||||||
$m->connect(
|
$m->connect(
|
||||||
'inbox.json',
|
'inbox.json',
|
||||||
['action' => 'apSharedInbox']
|
['action' => 'apInbox']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,7 +911,7 @@ class ActivityPubReturn
|
|||||||
* @param int32 $code Status Code
|
* @param int32 $code Status Code
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function error($m, $code = 500)
|
public static function error($m, $code = 400)
|
||||||
{
|
{
|
||||||
http_response_code($code);
|
http_response_code($code);
|
||||||
header('Content-Type: application/activity+json');
|
header('Content-Type: application/activity+json');
|
||||||
|
@ -1,130 +0,0 @@
|
|||||||
<?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>
|
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
|
||||||
* @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/
|
|
||||||
*/
|
|
||||||
if (!defined('GNUSOCIAL')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Actor's Inbox
|
|
||||||
*
|
|
||||||
* @category Plugin
|
|
||||||
* @package GNUsocial
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
|
||||||
* @link http://www.gnu.org/software/social/
|
|
||||||
*/
|
|
||||||
class apActorInboxAction extends ManagedAction
|
|
||||||
{
|
|
||||||
protected $needLogin = false;
|
|
||||||
protected $canPost = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the Actor Inbox request
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function handle()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$profile = Profile::getByID($this->trimmed('id'));
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error('Invalid Actor URI.', 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$profile->isLocal()) {
|
|
||||||
ActivityPubReturn::error('This is not a local user.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
||||||
ActivityPubReturn::error('C2S not implemented just yet.');
|
|
||||||
}
|
|
||||||
|
|
||||||
common_debug('ActivityPub Inbox: Received a POST request.');
|
|
||||||
$data = file_get_contents('php://input');
|
|
||||||
common_debug('ActivityPub Inbox: Request contents: '.$data);
|
|
||||||
$data = json_decode(file_get_contents('php://input'), true);
|
|
||||||
|
|
||||||
// Validate data
|
|
||||||
if (!(isset($data['type']))) {
|
|
||||||
ActivityPubReturn::error('Type was not specified.');
|
|
||||||
}
|
|
||||||
if (!isset($data['actor'])) {
|
|
||||||
ActivityPubReturn::error('Actor was not specified.');
|
|
||||||
}
|
|
||||||
if (!isset($data['object'])) {
|
|
||||||
ActivityPubReturn::error('Object was not specified.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get valid Actor object
|
|
||||||
try {
|
|
||||||
$actor_profile = ActivityPub_explorer::get_profile_from_url($data['actor']);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error($e->getMessage(), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cc = [$profile];
|
|
||||||
|
|
||||||
// Process request
|
|
||||||
define('INBOX_HANDLERS', __DIR__ . DIRECTORY_SEPARATOR . 'inbox' . DIRECTORY_SEPARATOR);
|
|
||||||
switch ($data['type']) {
|
|
||||||
// Data available:
|
|
||||||
// Profile $actor_profile Actor performing the action
|
|
||||||
// string|object $data->object Object to be handled
|
|
||||||
// Array|String $cc Destinataries
|
|
||||||
// Profile $profile Local user to whom this action is directed
|
|
||||||
case 'Create':
|
|
||||||
$cc = array_merge ([$profile], $data['object']['cc']);
|
|
||||||
require_once INBOX_HANDLERS . 'Create.php';
|
|
||||||
break;
|
|
||||||
case 'Follow':
|
|
||||||
require_once INBOX_HANDLERS . 'Follow.php';
|
|
||||||
break;
|
|
||||||
case 'Like':
|
|
||||||
require_once INBOX_HANDLERS . 'Like.php';
|
|
||||||
break;
|
|
||||||
case 'Announce':
|
|
||||||
require_once INBOX_HANDLERS . 'Announce.php';
|
|
||||||
break;
|
|
||||||
case 'Undo':
|
|
||||||
require_once INBOX_HANDLERS . 'Undo.php';
|
|
||||||
break;
|
|
||||||
case 'Delete':
|
|
||||||
require_once INBOX_HANDLERS . 'Delete.php';
|
|
||||||
break;
|
|
||||||
case 'Accept':
|
|
||||||
require_once INBOX_HANDLERS . 'Accept.php';
|
|
||||||
break;
|
|
||||||
case 'Reject':
|
|
||||||
require_once INBOX_HANDLERS . 'Reject.php';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ActivityPubReturn::error('Invalid type value.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -29,30 +29,42 @@ if (!defined('GNUSOCIAL')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate data
|
/**
|
||||||
if (!isset($data['object']['type'])) {
|
* Inbox Request Handler
|
||||||
ActivityPubReturn::error("Type was not specified.");
|
*
|
||||||
}
|
* @category Plugin
|
||||||
|
* @package GNUsocial
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://www.gnu.org/software/social/
|
||||||
|
*/
|
||||||
|
class apInboxAction extends ManagedAction
|
||||||
|
{
|
||||||
|
protected $needLogin = false;
|
||||||
|
protected $canPost = true;
|
||||||
|
|
||||||
switch ($data['object']['type']) {
|
/**
|
||||||
case "Follow":
|
* Handle the Inbox request
|
||||||
// Validate data
|
*
|
||||||
if (!isset($data['object']['object'])) {
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
ActivityPubReturn::error("Object Actor URL was not specified.");
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function handle()
|
||||||
|
{
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
ActivityPubReturn::error('Only POST requests allowed.');
|
||||||
}
|
}
|
||||||
// Get valid Object profile
|
|
||||||
|
common_debug('ActivityPub Shared Inbox: Received a POST request.');
|
||||||
|
$data = file_get_contents('php://input');
|
||||||
|
common_debug('ActivityPub Shared Inbox: Request contents: '.$data);
|
||||||
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$object_profile = new Activitypub_explorer;
|
new Activitypub_inbox_handler($data);
|
||||||
$object_profile = $object_profile->lookup($data['object']['object'])[0];
|
ActivityPubReturn::answer();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error("Invalid Object Actor URL.", 404);
|
ActivityPubReturn::error($e->getMessage());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$pending_list = new Activitypub_pending_follow_requests($actor_profile->getID(), $object_profile->getID());
|
|
||||||
$pending_list->remove();
|
|
||||||
ActivityPubReturn::answer(); // You are now being followed by this person.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ActivityPubReturn::error("Invalid object type.");
|
|
||||||
break;
|
|
||||||
}
|
}
|
@ -1,121 +0,0 @@
|
|||||||
<?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>
|
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
|
||||||
* @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/
|
|
||||||
*/
|
|
||||||
if (!defined('GNUSOCIAL')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shared Inbox Handler
|
|
||||||
*
|
|
||||||
* @category Plugin
|
|
||||||
* @package GNUsocial
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
|
||||||
* @link http://www.gnu.org/software/social/
|
|
||||||
*/
|
|
||||||
class apSharedInboxAction extends ManagedAction
|
|
||||||
{
|
|
||||||
protected $needLogin = false;
|
|
||||||
protected $canPost = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the Shared Inbox request
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function handle()
|
|
||||||
{
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
||||||
ActivityPubReturn::error('Only POST requests allowed.');
|
|
||||||
}
|
|
||||||
|
|
||||||
common_debug('ActivityPub Shared Inbox: Received a POST request.');
|
|
||||||
$data = file_get_contents('php://input');
|
|
||||||
common_debug('ActivityPub Shared Inbox: Request contents: '.$data);
|
|
||||||
$data = json_decode(file_get_contents('php://input'), true);
|
|
||||||
|
|
||||||
// Validate data
|
|
||||||
if (!isset($data['type'])) {
|
|
||||||
ActivityPubReturn::error('Type was not specified.');
|
|
||||||
}
|
|
||||||
if (!isset($data['actor'])) {
|
|
||||||
ActivityPubReturn::error('Actor was not specified.');
|
|
||||||
}
|
|
||||||
if (!isset($data['object'])) {
|
|
||||||
ActivityPubReturn::error('Object was not specified.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get valid Actor object
|
|
||||||
try {
|
|
||||||
$actor_profile = ActivityPub_explorer::get_profile_from_url($data['actor']);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error($e->getMessage(), 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cc = [];
|
|
||||||
|
|
||||||
// Process request
|
|
||||||
define('INBOX_HANDLERS', __DIR__ . DIRECTORY_SEPARATOR . 'inbox' . DIRECTORY_SEPARATOR);
|
|
||||||
switch ($data['type']) {
|
|
||||||
// Data available:
|
|
||||||
// Profile $actor_profile Actor performing the action
|
|
||||||
// string|object $data->object Object to be handled
|
|
||||||
// Array|String $cc Destinataries
|
|
||||||
// string|object $data->object
|
|
||||||
case 'Create':
|
|
||||||
$cc = $data['object']['cc'];
|
|
||||||
$res = $data['object'];
|
|
||||||
require_once INBOX_HANDLERS . 'Create.php';
|
|
||||||
break;
|
|
||||||
case 'Follow':
|
|
||||||
require_once INBOX_HANDLERS . 'Follow.php';
|
|
||||||
break;
|
|
||||||
case 'Like':
|
|
||||||
require_once INBOX_HANDLERS . 'Like.php';
|
|
||||||
break;
|
|
||||||
case 'Announce':
|
|
||||||
require_once INBOX_HANDLERS . 'Announce.php';
|
|
||||||
break;
|
|
||||||
case 'Undo':
|
|
||||||
require_once INBOX_HANDLERS . 'Undo.php';
|
|
||||||
break;
|
|
||||||
case 'Delete':
|
|
||||||
require_once INBOX_HANDLERS . 'Delete.php';
|
|
||||||
break;
|
|
||||||
case 'Accept':
|
|
||||||
require_once INBOX_HANDLERS . 'Accept.php';
|
|
||||||
break;
|
|
||||||
case 'Reject':
|
|
||||||
require_once INBOX_HANDLERS . 'Reject.php';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ActivityPubReturn::error('Invalid type value.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
<?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>
|
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
|
||||||
* @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/
|
|
||||||
*/
|
|
||||||
if (!defined('GNUSOCIAL')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
$object_notice = ActivityPubPlugin::grab_notice_from_url($data['object']);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error('Invalid Object specified.');
|
|
||||||
}
|
|
||||||
$object_notice->repeat($actor_profile, 'ActivityPub');
|
|
||||||
ActivityPubReturn::answer();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error($e->getMessage(), 403);
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
<?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>
|
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
|
||||||
* @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/
|
|
||||||
*/
|
|
||||||
if (!defined('GNUSOCIAL')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$valid_object_types = ['Note'];
|
|
||||||
|
|
||||||
try {
|
|
||||||
Activitypub_notice::validate_remote_notice($res);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
common_debug('ActivityPub Inbox Create Note: Invalid note: '.$e->getMessage());
|
|
||||||
ActivityPubReturn::error($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$settings = [];
|
|
||||||
|
|
||||||
if (isset($res['inReplyTo'])) {
|
|
||||||
$settings['inReplyTo'] = $res['inReplyTo'];
|
|
||||||
}
|
|
||||||
if (isset($res['latitude'])) {
|
|
||||||
$settings['latitude'] = $res['latitude'];
|
|
||||||
}
|
|
||||||
if (isset($res['longitude'])) {
|
|
||||||
$settings['longitude'] = $res['longitude'];
|
|
||||||
}
|
|
||||||
if (isset($res['attachment'])) {
|
|
||||||
$settings['attachment'] = $res['attachment'];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Activitypub_notice::create_notice(
|
|
||||||
$actor_profile,
|
|
||||||
$res['id'],
|
|
||||||
$res['url'],
|
|
||||||
$res['content'],
|
|
||||||
$cc,
|
|
||||||
$settings
|
|
||||||
);
|
|
||||||
ActivityPubReturn::answer();
|
|
||||||
} catch (AlreadyFulfilledException $e) {
|
|
||||||
// Notice URI already exists
|
|
||||||
common_debug('ActivityPub Inbox Create Note: Note already exists: '.$e->getMessage());
|
|
||||||
ActivityPubReturn::error('Note already exists.', 202);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
common_debug('ActivityPub Inbox Create Note: Failed Create Note: '.$e->getMessage());
|
|
||||||
ActivityPubReturn::error($e->getMessage());
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
<?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>
|
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
|
||||||
* @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/
|
|
||||||
*/
|
|
||||||
if (!defined('GNUSOCIAL')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$notice = ActivityPubPlugin::grab_notice_from_url($data['object']);
|
|
||||||
$notice->deleteAs($actor_profile);
|
|
||||||
ActivityPubReturn::answer();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error($e->getMessage(), 403);
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
<?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>
|
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
|
||||||
* @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/
|
|
||||||
*/
|
|
||||||
if (!defined('GNUSOCIAL')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate Object
|
|
||||||
if (!filter_var($data['object'], FILTER_VALIDATE_URL)) {
|
|
||||||
ActivityPubReturn::error('Invalid Object Actor URL.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure valid Object profile
|
|
||||||
try {
|
|
||||||
if (!isset($profile)) {
|
|
||||||
$object_profile = new Activitypub_explorer;
|
|
||||||
$object_profile = $object_profile->lookup($data['object'])[0];
|
|
||||||
} else {
|
|
||||||
$object_profile = $profile;
|
|
||||||
unset($profile);
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error('Invalid Object Actor URL.', 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Actor's Aprofile
|
|
||||||
$actor_aprofile = Activitypub_profile::from_profile($actor_profile);
|
|
||||||
|
|
||||||
if (!Subscription::exists($actor_profile, $object_profile)) {
|
|
||||||
Subscription::start($actor_profile, $object_profile);
|
|
||||||
common_debug('ActivityPubPlugin: Accepted Follow request from '.$data['actor'].' to '.$data['object']);
|
|
||||||
|
|
||||||
// Notify remote instance that we have accepted their request
|
|
||||||
common_debug('ActivityPubPlugin: Notifying remote instance that we have accepted their Follow request request from '.$data['actor'].' to '.$data['object']);
|
|
||||||
$postman = new Activitypub_postman($actor_profile, [$actor_aprofile]);
|
|
||||||
$postman->follow();
|
|
||||||
ActivityPubReturn::answer();
|
|
||||||
} else {
|
|
||||||
common_debug('ActivityPubPlugin: Received a repeated Follow request from '.$data['actor'].' to '.$data['object']);
|
|
||||||
ActivityPubReturn::error('Already following.', 202);
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
<?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>
|
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
|
||||||
* @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/
|
|
||||||
*/
|
|
||||||
if (!defined('GNUSOCIAL')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
$object_notice = ActivityPubPlugin::grab_notice_from_url($data['object']);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error('Invalid Object specified.');
|
|
||||||
}
|
|
||||||
Fave::addNew($actor_profile, $object_notice);
|
|
||||||
ActivityPubReturn::answer();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error($e->getMessage(), 403);
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
<?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>
|
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
|
||||||
* @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/
|
|
||||||
*/
|
|
||||||
if (!defined('GNUSOCIAL')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a dummy file as there is nothing to do if we fall in this case
|
|
@ -1,80 +0,0 @@
|
|||||||
<?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>
|
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
|
||||||
* @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/
|
|
||||||
*/
|
|
||||||
if (!defined('GNUSOCIAL')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate data
|
|
||||||
if (!isset($data['type'])) {
|
|
||||||
ActivityPubReturn::error('Type was not specified.');
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($data['object']['type']) {
|
|
||||||
case 'Like':
|
|
||||||
try {
|
|
||||||
// Validate data
|
|
||||||
if (!isset($data['object']['object'])) {
|
|
||||||
ActivityPubReturn::error('Notice URI was not specified.');
|
|
||||||
}
|
|
||||||
Fave::removeEntry($actor_profile, ActivityPubPlugin::grab_notice_from_url($data['object']['object']));
|
|
||||||
// Notice disfavorited successfully.
|
|
||||||
ActivityPubReturn::answer();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error($e->getMessage(), 403);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'Follow':
|
|
||||||
// Validate data
|
|
||||||
if (!isset($data['object']['object'])) {
|
|
||||||
ActivityPubReturn::error('Object Actor URL was not specified.');
|
|
||||||
}
|
|
||||||
// Get valid Object profile
|
|
||||||
try {
|
|
||||||
$object_profile = new Activitypub_explorer;
|
|
||||||
$object_profile = $object_profile->lookup($data['object']['object'])[0];
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error('Invalid Object Actor URL.', 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Subscription::exists($actor_profile, $object_profile)) {
|
|
||||||
Subscription::cancel($actor_profile, $object_profile);
|
|
||||||
// You are no longer following this person.
|
|
||||||
ActivityPubReturn::answer();
|
|
||||||
} else {
|
|
||||||
// 409: You are not following this person already.
|
|
||||||
ActivityPubReturn::answer();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'Announce':
|
|
||||||
// This is a dummy entry point as GNU Social doesn't allow Undo Announce
|
|
||||||
ActivityPubReturn::answer();
|
|
||||||
// no break
|
|
||||||
default:
|
|
||||||
ActivityPubReturn::error('Invalid object type.');
|
|
||||||
break;
|
|
||||||
}
|
|
@ -61,4 +61,32 @@ class Activitypub_accept extends Managed_DataObject
|
|||||||
];
|
];
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies if a given object is acceptable for an Accept Activity.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Array $object
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function validate_object($object)
|
||||||
|
{
|
||||||
|
if (!is_array($object)) {
|
||||||
|
throw new Exception('Invalid Object Format for Accept Activity.');
|
||||||
|
}
|
||||||
|
if (!isset($object['type'])) {
|
||||||
|
throw new Exception('Object type was not specified for Accept Activity.');
|
||||||
|
}
|
||||||
|
switch ($object['type']) {
|
||||||
|
case 'Follow':
|
||||||
|
// Validate data
|
||||||
|
if (!filter_var($object['object'], FILTER_VALIDATE_URL)) {
|
||||||
|
throw new Exception("Object is not a valid Object URI for Activity.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception('This is not a supported Object Type for Accept Activity.');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,11 +49,15 @@ class Activitypub_announce extends Managed_DataObject
|
|||||||
*/
|
*/
|
||||||
public static function announce_to_array($actor, $object)
|
public static function announce_to_array($actor, $object)
|
||||||
{
|
{
|
||||||
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
$res = [
|
||||||
"type" => "Announce",
|
'@context' => [
|
||||||
"actor" => $actor,
|
'https://www.w3.org/ns/activitystreams',
|
||||||
"object" => $object
|
'https://w3id.org/security/v1'
|
||||||
);
|
],
|
||||||
|
"type" => "Announce",
|
||||||
|
"actor" => $actor,
|
||||||
|
"object" => $object
|
||||||
|
];
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,18 +50,22 @@ class Activitypub_attachment extends Managed_DataObject
|
|||||||
public static function attachment_to_array($attachment)
|
public static function attachment_to_array($attachment)
|
||||||
{
|
{
|
||||||
$res = [
|
$res = [
|
||||||
'type' => 'Document',
|
'@context' => [
|
||||||
'mediaType' => $attachment->mimetype,
|
'https://www.w3.org/ns/activitystreams',
|
||||||
'url' => $attachment->getUrl(),
|
'https://w3id.org/security/v1'
|
||||||
'size' => intval($attachment->size), // $attachment->getSize ()
|
],
|
||||||
'name' => $attachment->getTitle(),
|
'type' => 'Document',
|
||||||
|
'mediaType' => $attachment->mimetype,
|
||||||
|
'url' => $attachment->getUrl(),
|
||||||
|
'size' => intval($attachment->size), // $attachment->getSize ()
|
||||||
|
'name' => $attachment->getTitle(),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
if (substr($res["mediaType"], 0, 5) == "image") {
|
if (substr($res["mediaType"], 0, 5) == "image") {
|
||||||
$res["meta"]= [
|
$res["meta"]= [
|
||||||
'width' => $attachment->width,
|
'width' => $attachment->width,
|
||||||
'height' => $attachment->height
|
'height' => $attachment->height
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,10 @@ class Activitypub_create extends Managed_DataObject
|
|||||||
public static function create_to_array($id, $actor, $object)
|
public static function create_to_array($id, $actor, $object)
|
||||||
{
|
{
|
||||||
$res = [
|
$res = [
|
||||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => [
|
||||||
|
'https://www.w3.org/ns/activitystreams',
|
||||||
|
'https://w3id.org/security/v1'
|
||||||
|
],
|
||||||
'id' => $id.'/create',
|
'id' => $id.'/create',
|
||||||
'type' => 'Create',
|
'type' => 'Create',
|
||||||
'to' => $object['to'],
|
'to' => $object['to'],
|
||||||
@ -61,4 +64,29 @@ class Activitypub_create extends Managed_DataObject
|
|||||||
];
|
];
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies if a given object is acceptable for a Create Activity.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Array $object
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function validate_object($object)
|
||||||
|
{
|
||||||
|
if (!is_array($object)) {
|
||||||
|
throw new Exception('Invalid Object Format for Create Activity.');
|
||||||
|
}
|
||||||
|
if (!isset($object['type'])) {
|
||||||
|
throw new Exception('Object type was not specified for Create Activity.');
|
||||||
|
}
|
||||||
|
switch ($object['type']) {
|
||||||
|
case 'Note':
|
||||||
|
// Validate data
|
||||||
|
Activitypub_notice::validate_note($object);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception('This is not a supported Object Type for Create Activity.');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,10 @@ 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' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => [
|
||||||
|
'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,
|
||||||
|
@ -50,8 +50,8 @@ class Activitypub_error extends Managed_DataObject
|
|||||||
public static function error_message_to_array($m)
|
public static function error_message_to_array($m)
|
||||||
{
|
{
|
||||||
$res = [
|
$res = [
|
||||||
'error'=> $m
|
'error'=> $m
|
||||||
];
|
];
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,4 +62,34 @@ class Activitypub_follow extends Managed_DataObject
|
|||||||
];
|
];
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a Follow Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Profile $actor_profile Remote Actor
|
||||||
|
* @param string $object Local Actor
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function follow($actor_profile, $object)
|
||||||
|
{
|
||||||
|
// Get Actor's Aprofile
|
||||||
|
$actor_aprofile = Activitypub_profile::from_profile($actor_profile);
|
||||||
|
|
||||||
|
// Get Object profile
|
||||||
|
$object_profile = new Activitypub_explorer;
|
||||||
|
$object_profile = $object_profile->lookup($object)[0];
|
||||||
|
|
||||||
|
if (!Subscription::exists($actor_profile, $object_profile)) {
|
||||||
|
Subscription::start($actor_profile, $object_profile);
|
||||||
|
common_debug('ActivityPubPlugin: Accepted Follow request from '.ActivityPubPlugin::actor_uri($actor_profile).' to '.$object);
|
||||||
|
} else {
|
||||||
|
common_debug('ActivityPubPlugin: Received a repeated Follow request from '.ActivityPubPlugin::actor_uri($actor_profile).' to '.$object);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify remote instance that we have accepted their request
|
||||||
|
common_debug('ActivityPubPlugin: Notifying remote instance that we have accepted their Follow request request from '.ActivityPubPlugin::actor_uri($actor_profile).' to '.$object);
|
||||||
|
$postman = new Activitypub_postman($actor_profile, [$actor_aprofile]);
|
||||||
|
$postman->accept_follow();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,10 @@ 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' => [
|
||||||
|
'https://www.w3.org/ns/activitystreams',
|
||||||
|
'https://w3id.org/security/v1'
|
||||||
|
],
|
||||||
"type" => "Mention",
|
"type" => "Mention",
|
||||||
"href" => $href,
|
"href" => $href,
|
||||||
"name" => $name
|
"name" => $name
|
||||||
|
@ -72,12 +72,15 @@ 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' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => [
|
||||||
|
'https://www.w3.org/ns/activitystreams',
|
||||||
|
'https://w3id.org/security/v1'
|
||||||
|
],
|
||||||
'id' => $notice->getUrl(),
|
'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(),
|
||||||
'atributtedTo' => ActivityPubPlugin::actor_uri($profile),
|
'attributedTo' => ActivityPubPlugin::actor_uri($profile),
|
||||||
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||||
'cc' => $cc,
|
'cc' => $cc,
|
||||||
'atomUri' => $notice->getUrl(),
|
'atomUri' => $notice->getUrl(),
|
||||||
@ -107,21 +110,42 @@ class Activitypub_notice extends Managed_DataObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Notice via ActivityPub data.
|
* Create a Notice via ActivityPub Note Object.
|
||||||
* Returns created Notice.
|
* Returns created Notice.
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Profile $actor_profile
|
* @param Array $object
|
||||||
* @param int32 $id
|
* @param Profile|null $actor_profile
|
||||||
* @param string $url
|
|
||||||
* @param string $content
|
|
||||||
* @param array|string $cc
|
|
||||||
* @param array $settings possible keys: ['inReplyTo', 'latitude', 'longitude', 'attachment']
|
|
||||||
* @return Notice
|
* @return Notice
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function create_notice($actor_profile, $id, $url, $content, $cc, $settings)
|
public static function create_notice($object, $actor_profile = null)
|
||||||
{
|
{
|
||||||
|
$id = $object['id']; // int32
|
||||||
|
$url = $object['url']; // string
|
||||||
|
$content = $object['content']; // string
|
||||||
|
$cc = $object['cc']; // array|string
|
||||||
|
|
||||||
|
// possible keys: ['inReplyTo', 'latitude', 'longitude', 'attachment']
|
||||||
|
$settings = [];
|
||||||
|
if (isset($object['inReplyTo'])) {
|
||||||
|
$settings['inReplyTo'] = $object['inReplyTo'];
|
||||||
|
}
|
||||||
|
if (isset($object['latitude'])) {
|
||||||
|
$settings['latitude'] = $object['latitude'];
|
||||||
|
}
|
||||||
|
if (isset($object['longitude'])) {
|
||||||
|
$settings['longitude'] = $object['longitude'];
|
||||||
|
}
|
||||||
|
if (isset($object['attachment'])) {
|
||||||
|
$settings['attachment'] = $object['attachment'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure Actor Profile
|
||||||
|
if (is_null($actor_profile)) {
|
||||||
|
$actor_profile = ActivityPub_explorer::get_profile_from_url($object['actor']);
|
||||||
|
}
|
||||||
|
|
||||||
$act = new Activity();
|
$act = new Activity();
|
||||||
$act->verb = ActivityVerb::POST;
|
$act->verb = ActivityVerb::POST;
|
||||||
$act->time = time();
|
$act->time = time();
|
||||||
@ -150,6 +174,7 @@ class Activitypub_notice extends Managed_DataObject
|
|||||||
|
|
||||||
$imagefile = new ImageFile(null, $temp_filename);
|
$imagefile = new ImageFile(null, $temp_filename);
|
||||||
$filename = hash(File::FILEHASH_ALG, $imgData).image_type_to_extension($imagefile->type);
|
$filename = hash(File::FILEHASH_ALG, $imgData).image_type_to_extension($imagefile->type);
|
||||||
|
|
||||||
unset($imgData); // No need to carry this in memory.
|
unset($imgData); // No need to carry this in memory.
|
||||||
rename($temp_filename, File::path($filename));
|
rename($temp_filename, File::path($filename));
|
||||||
common_debug('ActivityPub Create Notice: Moved image from: '.$temp_filename.' to '.$filename);
|
common_debug('ActivityPub Create Notice: Moved image from: '.$temp_filename.' to '.$filename);
|
||||||
@ -158,11 +183,9 @@ class Activitypub_notice extends Managed_DataObject
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
common_debug('ActivityPub Create Notice: Something went wrong while processing the image from: '.$attach_url.' details: '.$e->getMessage());
|
common_debug('ActivityPub Create Notice: Something went wrong while processing the image from: '.$attach_url.' details: '.$e->getMessage());
|
||||||
unlink($temp_filename);
|
unlink($temp_filename);
|
||||||
$content .= ($content==='' ? '' : ' ') . $attach_url;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$content .= ($content==='' ? '' : ' ') . $attach_url;
|
|
||||||
}
|
}
|
||||||
|
$content .= ($content==='' ? '' : ' ') . '<br><a href="'.$attach_url.'">Remote Attachment Source</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this a reply?
|
// Is this a reply?
|
||||||
@ -181,12 +204,13 @@ class Activitypub_notice extends Managed_DataObject
|
|||||||
$discovery = new Activitypub_explorer;
|
$discovery = new Activitypub_explorer;
|
||||||
|
|
||||||
// Generate Cc objects
|
// Generate Cc objects
|
||||||
|
$cc_profiles = [];
|
||||||
if (is_array($cc)) {
|
if (is_array($cc)) {
|
||||||
// Remove duplicates from Cc actors set
|
// Remove duplicates from Cc actors set
|
||||||
array_unique($cc);
|
array_unique($cc);
|
||||||
foreach ($cc as $cc_url) {
|
foreach ($cc as $cc_url) {
|
||||||
try {
|
try {
|
||||||
$cc = array_merge($cc, $discovery->lookup($cc_url));
|
$cc_profiles = array_merge($cc_profiles, $discovery->lookup($cc_url));
|
||||||
} 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
|
||||||
}
|
}
|
||||||
@ -195,7 +219,7 @@ class Activitypub_notice extends Managed_DataObject
|
|||||||
// No need to do anything else at this point, let's just break out the if
|
// No need to do anything else at this point, let's just break out the if
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
$cc = array_merge($cc, $discovery->lookup($cc));
|
$cc_profiles = $discovery->lookup($cc);
|
||||||
} 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
|
||||||
}
|
}
|
||||||
@ -203,8 +227,8 @@ class Activitypub_notice extends Managed_DataObject
|
|||||||
|
|
||||||
unset($discovery);
|
unset($discovery);
|
||||||
|
|
||||||
foreach ($cc as $tp) {
|
foreach ($cc_profiles as $cp) {
|
||||||
$act->context->attention[ActivityPubPlugin::actor_uri($tp)] = 'http://activitystrea.ms/schema/1.0/person';
|
$act->context->attention[ActivityPubPlugin::actor_uri($cp)] = 'http://activitystrea.ms/schema/1.0/person';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add location if that is set
|
// Add location if that is set
|
||||||
@ -224,56 +248,51 @@ class Activitypub_notice extends Managed_DataObject
|
|||||||
// Finally add the activity object to our activity
|
// Finally add the activity object to our activity
|
||||||
$act->objects[] = $actobj;
|
$act->objects[] = $actobj;
|
||||||
|
|
||||||
try {
|
$note = Notice::saveActivity($act, $actor_profile, $options);
|
||||||
$note = Notice::saveActivity($act, $actor_profile, $options);
|
if (ActivityPubPlugin::$store_images_from_remote_notes_attachments && isset($mediaFile)) {
|
||||||
if (ActivityPubPlugin::$store_images_from_remote_notes_attachments && isset($mediaFile)) {
|
$mediaFile->attachToNotice($note);
|
||||||
$mediaFile->attachToNotice($note);
|
|
||||||
}
|
|
||||||
return $note;
|
|
||||||
} catch (Exception $e) {
|
|
||||||
throw $e;
|
|
||||||
}
|
}
|
||||||
|
return $note;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates a remote notice.
|
* Validates a note.
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Array $data
|
* @param Array $object
|
||||||
* @return boolean true in case of success
|
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function validate_remote_notice($data)
|
public static function validate_note($object)
|
||||||
{
|
{
|
||||||
/*if (!isset($data['attributedTo'])) {
|
if (!isset($object['attributedTo'])) {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because attributedTo was not specified.');
|
common_debug('ActivityPub Notice Validator: Rejected because attributedTo was not specified.');
|
||||||
throw new Exception('No attributedTo specified.');
|
throw new Exception('No attributedTo specified.');
|
||||||
}
|
}
|
||||||
if (!isset($data['id'])) {
|
if (!isset($object['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.');
|
||||||
throw new Exception('Object ID not specified.');
|
throw new Exception('Object ID not specified.');
|
||||||
} elseif (!filter_var($data['id'], FILTER_VALIDATE_URL)) {
|
} elseif (!filter_var($object['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.');
|
||||||
throw new Exception('Invalid Object ID.');
|
throw new Exception('Invalid Object ID.');
|
||||||
}
|
}
|
||||||
if (!isset($data['type']) || $data['type'] !== 'Note') {
|
if (!isset($object['type']) || $object['type'] !== 'Note') {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because of Type.');
|
common_debug('ActivityPub Notice Validator: Rejected because of Type.');
|
||||||
throw new Exception('Invalid Object type.');
|
throw new Exception('Invalid Object type.');
|
||||||
}
|
}
|
||||||
if (!isset($data['content'])) {
|
if (!isset($object['content'])) {
|
||||||
common_debug('ActivityPub Notice Validator: Rejected because Content was not specified.');
|
common_debug('ActivityPub Notice Validator: Rejected because Content was not specified.');
|
||||||
throw new Exception('Object content was not specified.');
|
throw new Exception('Object content was not specified.');
|
||||||
}
|
}
|
||||||
if (!isset($data['url'])) {
|
if (!isset($object['url'])) {
|
||||||
throw new Exception('Object URL was not specified.');
|
throw new Exception('Object URL was not specified.');
|
||||||
} elseif (!filter_var($data['url'], FILTER_VALIDATE_URL)) {
|
} elseif (!filter_var($object['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.');
|
||||||
throw new Exception('Invalid Object URL.');
|
throw new Exception('Invalid Object URL.');
|
||||||
}
|
}
|
||||||
if (!isset($data['cc'])) {
|
if (!isset($object['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.');
|
||||||
throw new Exception('Object CC was not specified.');
|
throw new Exception('Object CC was not specified.');
|
||||||
}*/
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ class Activitypub_profile extends Managed_DataObject
|
|||||||
'following' => common_local_url("apActorFollowing", array("id" => $id)),
|
'following' => common_local_url("apActorFollowing", array("id" => $id)),
|
||||||
'followers' => common_local_url("apActorFollowers", array("id" => $id)),
|
'followers' => common_local_url("apActorFollowers", array("id" => $id)),
|
||||||
'liked' => common_local_url("apActorLiked", array("id" => $id)),
|
'liked' => common_local_url("apActorLiked", array("id" => $id)),
|
||||||
'inbox' => common_local_url("apActorInbox", array("id" => $id)),
|
'inbox' => common_local_url("apInbox", array("id" => $id)),
|
||||||
'preferredUsername' => $profile->getNickname(),
|
'preferredUsername' => $profile->getNickname(),
|
||||||
'name' => $profile->getBestName(),
|
'name' => $profile->getBestName(),
|
||||||
'summary' => ($desc = $profile->getDescription()) == null ? "" : $desc,
|
'summary' => ($desc = $profile->getDescription()) == null ? "" : $desc,
|
||||||
@ -128,7 +128,7 @@ class Activitypub_profile extends Managed_DataObject
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($profile->isLocal()) {
|
if ($profile->isLocal()) {
|
||||||
$res['endpoints']['sharedInbox'] = common_local_url('apSharedInbox');
|
$res['endpoints']['sharedInbox'] = common_local_url('apInbox');
|
||||||
} else {
|
} else {
|
||||||
$aprofile = new Activitypub_profile();
|
$aprofile = new Activitypub_profile();
|
||||||
$aprofile = $aprofile->from_profile($profile);
|
$aprofile = $aprofile->from_profile($profile);
|
||||||
|
@ -49,10 +49,14 @@ class Activitypub_reject extends Managed_DataObject
|
|||||||
*/
|
*/
|
||||||
public static function reject_to_array($object)
|
public static function reject_to_array($object)
|
||||||
{
|
{
|
||||||
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
$res = [
|
||||||
"type" => "Reject",
|
'@context' => [
|
||||||
"object" => $object
|
'https://www.w3.org/ns/activitystreams',
|
||||||
);
|
'https://w3id.org/security/v1'
|
||||||
|
],
|
||||||
|
"type" => "Reject",
|
||||||
|
"object" => $object
|
||||||
|
];
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,16 +50,13 @@ 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'
|
||||||
"@language" => "en"
|
],
|
||||||
]
|
'name' => $tag,
|
||||||
],
|
'url' => common_local_url('tag', ['tag' => $tag])
|
||||||
'name' => $tag,
|
];
|
||||||
'url' => common_local_url('tag', array('tag' => $tag))
|
|
||||||
];
|
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,4 +61,33 @@ class Activitypub_undo extends Managed_DataObject
|
|||||||
];
|
];
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies if a given object is acceptable for a Undo Activity.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Array $object
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function validate_object($object)
|
||||||
|
{
|
||||||
|
if (!is_array($object)) {
|
||||||
|
throw new Exception('Invalid Object Format for Undo Activity.');
|
||||||
|
}
|
||||||
|
if (!isset($object['type'])) {
|
||||||
|
throw new Exception('Object type was not specified for Undo Activity.');
|
||||||
|
}
|
||||||
|
switch ($object['type']) {
|
||||||
|
case 'Follow':
|
||||||
|
case 'Like':
|
||||||
|
// Validate data
|
||||||
|
if (!filter_var($object['object'], FILTER_VALIDATE_URL)) {
|
||||||
|
throw new Exception('Object is not a valid Object URI for Activity.');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception('This is not a supported Object Type for Undo Activity.');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
102
utils/Activitypub_activityverb2.php
Normal file
102
utils/Activitypub_activityverb2.php
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<?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>
|
||||||
|
* @author Daniel Supernault <danielsupernault@gmail.com>
|
||||||
|
* @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/
|
||||||
|
*/
|
||||||
|
if (!defined('GNUSOCIAL')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to hold a bunch of constant defining default verb types
|
||||||
|
*
|
||||||
|
* @category Plugin
|
||||||
|
* @package GNUsocial
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://www.gnu.org/software/social/
|
||||||
|
*/
|
||||||
|
class Activitypub_activityverb2 extends Managed_DataObject
|
||||||
|
{
|
||||||
|
const FULL_LIST =
|
||||||
|
[
|
||||||
|
'Accept' => 'https://www.w3.org/ns/activitystreams#Accept',
|
||||||
|
'TentativeAccept' => 'https://www.w3.org/ns/activitystreams#TentativeAccept',
|
||||||
|
'Add' => 'https://www.w3.org/ns/activitystreams#Add',
|
||||||
|
'Arrive' => 'https://www.w3.org/ns/activitystreams#Arrive',
|
||||||
|
'Create' => 'https://www.w3.org/ns/activitystreams#Create',
|
||||||
|
'Delete' => 'https://www.w3.org/ns/activitystreams#Delete',
|
||||||
|
'Follow' => 'https://www.w3.org/ns/activitystreams#Follow',
|
||||||
|
'Ignore' => 'https://www.w3.org/ns/activitystreams#Ignore',
|
||||||
|
'Join' => 'https://www.w3.org/ns/activitystreams#Join',
|
||||||
|
'Leave' => 'https://www.w3.org/ns/activitystreams#Leave',
|
||||||
|
'Like' => 'https://www.w3.org/ns/activitystreams#Like',
|
||||||
|
'Offer' => 'https://www.w3.org/ns/activitystreams#Offer',
|
||||||
|
'Invite' => 'https://www.w3.org/ns/activitystreams#Invite',
|
||||||
|
'Reject' => 'https://www.w3.org/ns/activitystreams#Reject',
|
||||||
|
'TentativeReject' => 'https://www.w3.org/ns/activitystreams#TentativeReject',
|
||||||
|
'Remove' => 'https://www.w3.org/ns/activitystreams#Remove',
|
||||||
|
'Undo' => 'https://www.w3.org/ns/activitystreams#Undo',
|
||||||
|
'Update' => 'https://www.w3.org/ns/activitystreams#Update',
|
||||||
|
'View' => 'https://www.w3.org/ns/activitystreams#View',
|
||||||
|
'Listen' => 'https://www.w3.org/ns/activitystreams#Listen',
|
||||||
|
'Read' => 'https://www.w3.org/ns/activitystreams#Read',
|
||||||
|
'Move' => 'https://www.w3.org/ns/activitystreams#Move',
|
||||||
|
'Travel' => 'https://www.w3.org/ns/activitystreams#Travel',
|
||||||
|
'Announce' => 'https://www.w3.org/ns/activitystreams#Announce',
|
||||||
|
'Block' => 'https://www.w3.org/ns/activitystreams#Block',
|
||||||
|
'Flag' => 'https://www.w3.org/ns/activitystreams#Flag',
|
||||||
|
'Dislike' => 'https://www.w3.org/ns/activitystreams#Dislike',
|
||||||
|
'Question' => 'https://www.w3.org/ns/activitystreams#Question'
|
||||||
|
];
|
||||||
|
|
||||||
|
const KNOWN =
|
||||||
|
[
|
||||||
|
'Accept',
|
||||||
|
'Create',
|
||||||
|
'Delete',
|
||||||
|
'Follow',
|
||||||
|
'Like',
|
||||||
|
'Undo',
|
||||||
|
'Announce'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts canonical into verb.
|
||||||
|
*
|
||||||
|
* @author GNU Social
|
||||||
|
* @param string $verb
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function canonical($verb)
|
||||||
|
{
|
||||||
|
$ns = 'https://www.w3.org/ns/activitystreams#';
|
||||||
|
if (substr($verb, 0, mb_strlen($ns)) == $ns) {
|
||||||
|
return substr($verb, mb_strlen($ns));
|
||||||
|
} else {
|
||||||
|
return $verb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -32,9 +32,9 @@ class DiscoveryHints
|
|||||||
{
|
{
|
||||||
public static function fromXRD(XML_XRD $xrd)
|
public static function fromXRD(XML_XRD $xrd)
|
||||||
{
|
{
|
||||||
$hints = array();
|
$hints = [];
|
||||||
|
|
||||||
if (Event::handle('StartDiscoveryHintsFromXRD', array($xrd, &$hints))) {
|
if (Event::handle('StartDiscoveryHintsFromXRD', [$xrd, &$hints])) {
|
||||||
foreach ($xrd->links as $link) {
|
foreach ($xrd->links as $link) {
|
||||||
switch ($link->rel) {
|
switch ($link->rel) {
|
||||||
case WebFingerResource_Profile::PROFILEPAGE:
|
case WebFingerResource_Profile::PROFILEPAGE:
|
||||||
@ -55,7 +55,7 @@ class DiscoveryHints
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::handle('EndDiscoveryHintsFromXRD', array($xrd, &$hints));
|
Event::handle('EndDiscoveryHintsFromXRD', [$xrd, &$hints]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $hints;
|
return $hints;
|
||||||
@ -88,10 +88,10 @@ class DiscoveryHints
|
|||||||
$hcard = self::_hcard($body, $url);
|
$hcard = self::_hcard($body, $url);
|
||||||
|
|
||||||
if (empty($hcard)) {
|
if (empty($hcard)) {
|
||||||
return array();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$hints = array();
|
$hints = [];
|
||||||
|
|
||||||
// XXX: don't copy stuff into an array and then copy it again
|
// XXX: don't copy stuff into an array and then copy it again
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ class DiscoveryHints
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hcards = array();
|
$hcards = [];
|
||||||
|
|
||||||
foreach ($mf2['items'] as $item) {
|
foreach ($mf2['items'] as $item) {
|
||||||
if (!in_array('h-card', $item['type'])) {
|
if (!in_array('h-card', $item['type'])) {
|
||||||
|
296
utils/inbox_handler.php
Normal file
296
utils/inbox_handler.php
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
<?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>
|
||||||
|
* @author Daniel Supernault <danielsupernault@gmail.com>
|
||||||
|
* @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/
|
||||||
|
*/
|
||||||
|
if (!defined('GNUSOCIAL')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ActivityPub Inbox Handler
|
||||||
|
*
|
||||||
|
* @category Plugin
|
||||||
|
* @package GNUsocial
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://www.gnu.org/software/social/
|
||||||
|
*/
|
||||||
|
class Activitypub_inbox_handler
|
||||||
|
{
|
||||||
|
private $activity;
|
||||||
|
private $actor;
|
||||||
|
private $object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Inbox Handler to receive something from someone.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Array $activity Activity we are receiving
|
||||||
|
*/
|
||||||
|
public function __construct($activity)
|
||||||
|
{
|
||||||
|
$this->activity = $activity;
|
||||||
|
$this->object = $activity['object'];
|
||||||
|
|
||||||
|
// Validate Activity
|
||||||
|
$this->validate_activity();
|
||||||
|
|
||||||
|
// Get Actor's Profile
|
||||||
|
$this->actor = ActivityPub_explorer::get_profile_from_url($this->activity['actor']);
|
||||||
|
|
||||||
|
// Handle the Activity
|
||||||
|
$this->process();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if a given Activity is valid. Throws exception if not.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function validate_activity()
|
||||||
|
{
|
||||||
|
// Activity validation
|
||||||
|
// Validate data
|
||||||
|
if (!(isset($this->activity['type']))) {
|
||||||
|
throw new Exception('Activity Validation Failed: Type was not specified.');
|
||||||
|
}
|
||||||
|
if (!isset($this->activity['actor'])) {
|
||||||
|
throw new Exception('Activity Validation Failed: Actor was not specified.');
|
||||||
|
}
|
||||||
|
if (!isset($this->activity['object'])) {
|
||||||
|
throw new Exception('Activity Validation Failed: Object was not specified.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object validation
|
||||||
|
switch ($this->activity['type']) {
|
||||||
|
case 'Accept':
|
||||||
|
Activitypub_accept::validate_object($this->object);
|
||||||
|
break;
|
||||||
|
case 'Create':
|
||||||
|
Activitypub_create::validate_object($this->object);
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
case 'Follow':
|
||||||
|
case 'Like':
|
||||||
|
case 'Announce':
|
||||||
|
if (!filter_var($this->object, FILTER_VALIDATE_URL)) {
|
||||||
|
throw new Exception("Object is not a valid Object URI for Activity.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Undo':
|
||||||
|
Activitypub_undo::validate_object($this->object);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception('Unknown Activity Type.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the Activity to proper handler in order to be processed.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
*/
|
||||||
|
private function process()
|
||||||
|
{
|
||||||
|
switch ($this->activity['type']) {
|
||||||
|
case 'Accept':
|
||||||
|
$this->handle_accept($this->actor, $this->object);
|
||||||
|
break;
|
||||||
|
case 'Create':
|
||||||
|
$this->handle_create($this->actor, $this->object);
|
||||||
|
break;
|
||||||
|
case 'Delete':
|
||||||
|
$this->handle_delete($this->actor, $this->object);
|
||||||
|
break;
|
||||||
|
case 'Follow':
|
||||||
|
$this->handle_follow($this->actor, $this->object);
|
||||||
|
break;
|
||||||
|
case 'Like':
|
||||||
|
$this->handle_like($this->actor, $this->object);
|
||||||
|
break;
|
||||||
|
case 'Undo':
|
||||||
|
$this->handle_undo($this->actor, $this->object);
|
||||||
|
break;
|
||||||
|
case 'Announce':
|
||||||
|
$this->handle_announce($this->actor, $this->object);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles an Accept Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_accept($actor, $object)
|
||||||
|
{
|
||||||
|
switch ($object['type']) {
|
||||||
|
case 'Follow':
|
||||||
|
$this->handle_accept_follow($actor, $object);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles an Accept Follow Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_accept_follow($actor, $object)
|
||||||
|
{
|
||||||
|
// Get valid Object profile
|
||||||
|
$object_profile = new Activitypub_explorer;
|
||||||
|
$object_profile = $object_profile->lookup($object['object'])[0];
|
||||||
|
|
||||||
|
$pending_list = new Activitypub_pending_follow_requests($actor->getID(), $object_profile->getID());
|
||||||
|
$pending_list->remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a Create Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_create($actor, $object)
|
||||||
|
{
|
||||||
|
switch ($object['type']) {
|
||||||
|
case 'Note':
|
||||||
|
Activitypub_notice::create_notice($object, $actor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a Delete Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_delete($actor, $object)
|
||||||
|
{
|
||||||
|
$notice = ActivityPubPlugin::grab_notice_from_url($object['object']);
|
||||||
|
$notice->deleteAs($actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a Follow Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_follow($actor, $object)
|
||||||
|
{
|
||||||
|
Activitypub_follow::follow($actor, $object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a Like Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_like($actor, $object)
|
||||||
|
{
|
||||||
|
$notice = ActivityPubPlugin::grab_notice_from_url($object);
|
||||||
|
Fave::addNew($actor, $notice);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a Undo Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_undo($actor, $object)
|
||||||
|
{
|
||||||
|
switch ($object['type']) {
|
||||||
|
case 'Follow':
|
||||||
|
$this->handle_undo_follow($actor, $object['object']);
|
||||||
|
break;
|
||||||
|
case 'Like':
|
||||||
|
$this->handle_undo_like($actor, $object['object']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a Undo Like Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_undo_like($actor, $object)
|
||||||
|
{
|
||||||
|
$notice = ActivityPubPlugin::grab_notice_from_url($object);
|
||||||
|
Fave::removeEntry($actor, $notice);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a Undo Follow Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_undo_follow($actor, $object)
|
||||||
|
{
|
||||||
|
// Get Object profile
|
||||||
|
$object_profile = new Activitypub_explorer;
|
||||||
|
$object_profile = $object_profile->lookup($object)[0];
|
||||||
|
|
||||||
|
if (Subscription::exists($actor, $object_profile)) {
|
||||||
|
Subscription::cancel($actor, $object_profile);
|
||||||
|
// You are no longer following this person.
|
||||||
|
} else {
|
||||||
|
// 409: You are not following this person already.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a Announce Activity received by our inbox.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.upt.pt>
|
||||||
|
* @param Profile $actor Actor
|
||||||
|
* @param Array $object Activity
|
||||||
|
*/
|
||||||
|
private function handle_announce($actor, $object)
|
||||||
|
{
|
||||||
|
$object_notice = ActivityPubPlugin::grab_notice_from_url($object);
|
||||||
|
$object_notice->repeat($actor, 'ActivityPub');
|
||||||
|
}
|
||||||
|
}
|
@ -135,11 +135,39 @@ class Activitypub_postman
|
|||||||
public function undo_follow()
|
public function undo_follow()
|
||||||
{
|
{
|
||||||
$data = Activitypub_undo::undo_to_array(
|
$data = Activitypub_undo::undo_to_array(
|
||||||
Activitypub_follow::follow_to_array(
|
Activitypub_follow::follow_to_array(
|
||||||
ActivityPubPlugin::actor_uri($this->actor),
|
ActivityPubPlugin::actor_uri($this->actor),
|
||||||
$this->to[0]->getUrl()
|
$this->to[0]->getUrl()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
$res = $this->send(json_encode($data, JSON_UNESCAPED_SLASHES), $this->to[0]->get_inbox());
|
||||||
|
$res_body = json_decode($res->getBody()->getContents());
|
||||||
|
|
||||||
|
if ($res->getStatusCode() == 200 || $res->getStatusCode() == 202 || $res->getStatusCode() == 409) {
|
||||||
|
$pending_list = new Activitypub_pending_follow_requests($this->actor->getID(), $this->to[0]->getID());
|
||||||
|
$pending_list->remove();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isset($res_body[0]->error)) {
|
||||||
|
throw new Exception($res_body[0]->error);
|
||||||
|
}
|
||||||
|
throw new Exception("An unknown error occurred.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a Accept Follow notification to remote instance
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
*/
|
||||||
|
public function accept_follow()
|
||||||
|
{
|
||||||
|
$data = Activitypub_accept::accept_to_array(
|
||||||
|
Activitypub_follow::follow_to_array(
|
||||||
|
$this->to[0]->getUrl(),
|
||||||
|
ActivityPubPlugin::actor_uri($this->actor)
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
$res = $this->send(json_encode($data, JSON_UNESCAPED_SLASHES), $this->to[0]->get_inbox());
|
$res = $this->send(json_encode($data, JSON_UNESCAPED_SLASHES), $this->to[0]->get_inbox());
|
||||||
$res_body = json_decode($res->getBody()->getContents());
|
$res_body = json_decode($res->getBody()->getContents());
|
||||||
|
|
||||||
@ -278,7 +306,7 @@ class Activitypub_postman
|
|||||||
foreach ($this->to as $to_profile) {
|
foreach ($this->to as $to_profile) {
|
||||||
$i = $to_profile->get_inbox();
|
$i = $to_profile->get_inbox();
|
||||||
// Prevent delivering to self
|
// Prevent delivering to self
|
||||||
if ($i == [common_local_url('apSharedInbox')]) {
|
if ($i == [common_local_url('apInbox')]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$to_inboxes[] = $i;
|
$to_inboxes[] = $i;
|
||||||
|
Reference in New Issue
Block a user