Now the code is following most of PSR Various changes from various branches (some testing will be required) Fixed various issues
This commit is contained in:
parent
e377b87ff7
commit
eaad9423dd
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/vendor/
|
File diff suppressed because it is too large
Load Diff
@ -6,11 +6,10 @@ email, or any other method with the owners of this repository before making a ch
|
|||||||
Please note we have a code of conduct, please follow it in all your interactions with the project.
|
Please note we have a code of conduct, please follow it in all your interactions with the project.
|
||||||
|
|
||||||
# Coding Style
|
# Coding Style
|
||||||
- We are using [K&R Variant: Linux kernel](https://en.wikipedia.org/wiki/Indentation_style#Variant:_Linux_kernel) with spaces before every `(`.
|
- We follow every [PSR-2](https://www.php-fig.org/psr/psr-2/) ...
|
||||||
- Every function has a docblock explaining what it does and stating the author, parameters, types, return and exceptions
|
- ... except camelCase, that's too bad, we use snake_case
|
||||||
- We use snake_case
|
|
||||||
|
|
||||||
## Pull Request Process
|
## Merge Request Process
|
||||||
|
|
||||||
1. Ensure you strip any trailing spaces off
|
1. Ensure you strip any trailing spaces off
|
||||||
2. Increase the version numbers in any examples files and the README.md to the new version that this
|
2. Increase the version numbers in any examples files and the README.md to the new version that this
|
||||||
|
@ -67,4 +67,3 @@ License along with this program, in the file "COPYING". If not, see
|
|||||||
to your users under the same license. This is a legal requirement
|
to your users under the same license. This is a legal requirement
|
||||||
of using the software, and if you do not wish to share your
|
of using the software, and if you do not wish to share your
|
||||||
modifications, *YOU MAY NOT USE THIS PLUGIN*.
|
modifications, *YOU MAY NOT USE THIS PLUGIN*.
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,64 +40,62 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class apActorFollowersAction extends ManagedAction
|
class apActorFollowersAction extends ManagedAction
|
||||||
{
|
{
|
||||||
protected $needLogin = false;
|
protected $needLogin = false;
|
||||||
protected $canPost = true;
|
protected $canPost = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the Followers Collection request
|
* Handle the Followers Collection request
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function handle ()
|
protected function handle()
|
||||||
{
|
{
|
||||||
$nickname = $this->trimmed ('nickname');
|
try {
|
||||||
try {
|
$profile = Profile::getByID($this->trimmed('id'));
|
||||||
$user = User::getByNickname ($nickname);
|
$url = ActivityPubPlugin::actor_url($profile);
|
||||||
$profile = $user->getProfile ();
|
} catch (Exception $e) {
|
||||||
$url = $profile->profileurl;
|
ActivityPubReturn::error('Invalid Actor URI.', 404);
|
||||||
} catch (Exception $e) {
|
}
|
||||||
ActivityPubReturn::error ('Invalid username.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset ($_GET["page"])) {
|
if (!isset($_GET["page"])) {
|
||||||
$page = 1;
|
$page = 1;
|
||||||
} else {
|
} else {
|
||||||
$page = intval ($this->trimmed ('page'));
|
$page = intval($this->trimmed('page'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page <= 0) {
|
if ($page <= 0) {
|
||||||
ActivityPubReturn::error ('Invalid page number.');
|
ActivityPubReturn::error('Invalid page number.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fetch Followers */
|
/* Fetch Followers */
|
||||||
try {
|
try {
|
||||||
$since = ($page - 1) * PROFILES_PER_MINILIST;
|
$since = ($page - 1) * PROFILES_PER_MINILIST;
|
||||||
$limit = (($page - 1) == 0 ? 1 : $page) * PROFILES_PER_MINILIST;
|
$limit = (($page - 1) == 0 ? 1 : $page) * PROFILES_PER_MINILIST;
|
||||||
$sub = $profile->getSubscribers ($since, $limit);
|
$sub = $profile->getSubscribers($since, $limit);
|
||||||
} catch (NoResultException $e) {
|
} catch (NoResultException $e) {
|
||||||
ActivityPubReturn::error ('This user has no followers.');
|
ActivityPubReturn::error('This user has no followers.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate total items */
|
/* Calculate total items */
|
||||||
$total_subs = $profile->subscriberCount ();
|
$total_subs = $profile->subscriberCount();
|
||||||
$total_pages = ceil ($total_subs / PROFILES_PER_MINILIST);
|
$total_pages = ceil($total_subs / PROFILES_PER_MINILIST);
|
||||||
|
|
||||||
if ($total_pages == 0) {
|
if ($total_pages == 0) {
|
||||||
ActivityPubReturn::error ('This user has no followers.');
|
ActivityPubReturn::error('This user has no followers.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page > $total_pages) {
|
if ($page > $total_pages) {
|
||||||
ActivityPubReturn::error ("There are only {$total_pages} pages.");
|
ActivityPubReturn::error("There are only {$total_pages} pages.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get followers' URLs */
|
/* Get followers' URLs */
|
||||||
$subs = array ();
|
$subs = array();
|
||||||
while ($sub->fetch ()) {
|
while ($sub->fetch()) {
|
||||||
$subs[] = $sub->profileurl;
|
$subs[] = $sub->profileurl;
|
||||||
}
|
}
|
||||||
|
|
||||||
$res = [
|
$res = [
|
||||||
'@context' => [
|
'@context' => [
|
||||||
"https://www.w3.org/ns/activitystreams",
|
"https://www.w3.org/ns/activitystreams",
|
||||||
"https://w3id.org/security/v1",
|
"https://w3id.org/security/v1",
|
||||||
@ -110,6 +108,6 @@ class apActorFollowersAction extends ManagedAction
|
|||||||
'orderedItems' => $subs
|
'orderedItems' => $subs
|
||||||
];
|
];
|
||||||
|
|
||||||
ActivityPubReturn::answer ($res);
|
ActivityPubReturn::answer($res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,64 +40,62 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class apActorFollowingAction extends ManagedAction
|
class apActorFollowingAction extends ManagedAction
|
||||||
{
|
{
|
||||||
protected $needLogin = false;
|
protected $needLogin = false;
|
||||||
protected $canPost = true;
|
protected $canPost = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the Following Collection request
|
* Handle the Following Collection request
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function handle ()
|
protected function handle()
|
||||||
{
|
{
|
||||||
$nickname = $this->trimmed ('nickname');
|
try {
|
||||||
try {
|
$profile = Profile::getByID($this->trimmed('id'));
|
||||||
$user = User::getByNickname ($nickname);
|
$url = ActivityPubPlugin::actor_url($profile);
|
||||||
$profile = $user->getProfile ();
|
} catch (Exception $e) {
|
||||||
$url = $profile->profileurl;
|
ActivityPubReturn::error('Invalid Actor URI.', 404);
|
||||||
} catch (Exception $e) {
|
}
|
||||||
ActivityPubReturn::error ('Invalid username.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset ($_GET["page"])) {
|
if (!isset($_GET["page"])) {
|
||||||
$page = 1;
|
$page = 1;
|
||||||
} else {
|
} else {
|
||||||
$page = intval ($this->trimmed ('page'));
|
$page = intval($this->trimmed('page'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page <= 0) {
|
if ($page <= 0) {
|
||||||
ActivityPubReturn::error ('Invalid page number.');
|
ActivityPubReturn::error('Invalid page number.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fetch Following */
|
/* Fetch Following */
|
||||||
try {
|
try {
|
||||||
$since = ($page - 1) * PROFILES_PER_MINILIST;
|
$since = ($page - 1) * PROFILES_PER_MINILIST;
|
||||||
$limit = (($page - 1) == 0 ? 1 : $page) * PROFILES_PER_MINILIST;
|
$limit = (($page - 1) == 0 ? 1 : $page) * PROFILES_PER_MINILIST;
|
||||||
$sub = $profile->getSubscribed ($since, $limit);
|
$sub = $profile->getSubscribed($since, $limit);
|
||||||
} catch (NoResultException $e) {
|
} catch (NoResultException $e) {
|
||||||
ActivityPubReturn::error ('This user is not following anyone.');
|
ActivityPubReturn::error('This user is not following anyone.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate total items */
|
/* Calculate total items */
|
||||||
$total_subs = $profile->subscriptionCount();
|
$total_subs = $profile->subscriptionCount();
|
||||||
$total_pages = ceil ($total_subs / PROFILES_PER_MINILIST);
|
$total_pages = ceil($total_subs / PROFILES_PER_MINILIST);
|
||||||
|
|
||||||
if ($total_pages == 0) {
|
if ($total_pages == 0) {
|
||||||
ActivityPubReturn::error ('This user is not following anyone.');
|
ActivityPubReturn::error('This user is not following anyone.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($page > $total_pages) {
|
if ($page > $total_pages) {
|
||||||
ActivityPubReturn::error ("There are only {$total_pages} pages.");
|
ActivityPubReturn::error("There are only {$total_pages} pages.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get followed' URLs */
|
/* Get followed' URLs */
|
||||||
$subs = array ();
|
$subs = array();
|
||||||
while ($sub->fetch ()) {
|
while ($sub->fetch()) {
|
||||||
$subs[] = $sub->profileurl;
|
$subs[] = $sub->profileurl;
|
||||||
}
|
}
|
||||||
|
|
||||||
$res = [
|
$res = [
|
||||||
'@context' => [
|
'@context' => [
|
||||||
"https://www.w3.org/ns/activitystreams",
|
"https://www.w3.org/ns/activitystreams",
|
||||||
"https://w3id.org/security/v1",
|
"https://w3id.org/security/v1",
|
||||||
@ -110,6 +108,6 @@ class apActorFollowingAction extends ManagedAction
|
|||||||
'orderedItems' => $subs
|
'orderedItems' => $subs
|
||||||
];
|
];
|
||||||
|
|
||||||
ActivityPubReturn::answer ($res);
|
ActivityPubReturn::answer($res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,57 +40,59 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class apActorInboxAction extends ManagedAction
|
class apActorInboxAction extends ManagedAction
|
||||||
{
|
{
|
||||||
protected $needLogin = false;
|
protected $needLogin = false;
|
||||||
protected $canPost = true;
|
protected $canPost = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the Actor Inbox request
|
* Handle the Actor Inbox request
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function handle ()
|
protected function handle()
|
||||||
{
|
{
|
||||||
$nickname = $this->trimmed ('nickname');
|
try {
|
||||||
try {
|
$profile = Profile::getByID($this->trimmed('id'));
|
||||||
$user = User::getByNickname ($nickname);
|
} catch (Exception $e) {
|
||||||
$profile = $user->getProfile ();
|
ActivityPubReturn::error('Invalid Actor URI.', 404);
|
||||||
$url = $profile->profileurl;
|
}
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error ("Invalid username.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
ActivityPubReturn::error ("C2S not implemented just yet.");
|
ActivityPubReturn::error("C2S not implemented just yet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = json_decode (file_get_contents ('php://input'));
|
$data = json_decode(file_get_contents('php://input'));
|
||||||
|
|
||||||
// Validate data
|
// Validate data
|
||||||
if (!(isset ($data->type))) {
|
if (!(isset($data->type))) {
|
||||||
ActivityPubReturn::error ("Type was not specified.");
|
ActivityPubReturn::error("Type was not specified.");
|
||||||
}
|
}
|
||||||
if (!isset ($data->actor)) {
|
if (!isset($data->actor)) {
|
||||||
ActivityPubReturn::error ("Actor was not specified.");
|
ActivityPubReturn::error("Actor was not specified.");
|
||||||
}
|
}
|
||||||
if (!isset ($data->object)) {
|
if (!isset($data->object)) {
|
||||||
ActivityPubReturn::error ("Object was not specified.");
|
ActivityPubReturn::error("Object was not specified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get valid Actor object
|
// Get valid Actor object
|
||||||
try {
|
try {
|
||||||
require_once dirname (__DIR__) . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR . "explorer.php";
|
require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR . "explorer.php";
|
||||||
$actor_profile = new Activitypub_explorer;
|
$actor_profile = new Activitypub_explorer;
|
||||||
$actor_profile = $actor_profile->lookup ($data->actor);
|
$actor_profile = $actor_profile->lookup($data->actor);
|
||||||
$actor_profile = $actor_profile[0];
|
$actor_profile = $actor_profile[0];
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ("Invalid Actor.", 404);
|
ActivityPubReturn::error("Invalid Actor.", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$to_profiles = array ($user);
|
// Public To:
|
||||||
|
$public_to = array("https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"Public",
|
||||||
|
"as:Public");
|
||||||
|
|
||||||
// Process request
|
$to_profiles = array($profile);
|
||||||
switch ($data->type) {
|
|
||||||
|
// Process request
|
||||||
|
switch ($data->type) {
|
||||||
case "Create":
|
case "Create":
|
||||||
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Create.php";
|
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Create.php";
|
||||||
break;
|
break;
|
||||||
@ -109,8 +111,14 @@ class apActorInboxAction extends ManagedAction
|
|||||||
case "Announce":
|
case "Announce":
|
||||||
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Announce.php";
|
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Announce.php";
|
||||||
break;
|
break;
|
||||||
|
case "Accept":
|
||||||
|
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Accept.php";
|
||||||
|
break;
|
||||||
|
case "Reject":
|
||||||
|
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Reject.php";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ActivityPubReturn::error ("Invalid type value.");
|
ActivityPubReturn::error("Invalid type value.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
152
actions/apactorliked.php
Normal file
152
actions/apactorliked.php
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<?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 Liked Collection
|
||||||
|
*
|
||||||
|
* @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 apActorLikedAction extends ManagedAction
|
||||||
|
{
|
||||||
|
protected $needLogin = false;
|
||||||
|
protected $canPost = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the Liked Collection request
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function handle()
|
||||||
|
{
|
||||||
|
$nickname = $this->trimmed('nickname');
|
||||||
|
try {
|
||||||
|
$user = User::getByNickname($nickname);
|
||||||
|
$profile = $user->getProfile();
|
||||||
|
$url = $profile->profileurl;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
ActivityPubReturn::error('Invalid username.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$limit = intval($this->trimmed('limit'));
|
||||||
|
$since_id = intval($this->trimmed('since_id'));
|
||||||
|
$max_id = intval($this->trimmed('max_id'));
|
||||||
|
|
||||||
|
$limit = empty($limit) ? 40 : $limit; // Default is 40
|
||||||
|
$since_id = empty($since_id) ? null : $since_id;
|
||||||
|
$max_id = empty($max_id) ? null : $max_id;
|
||||||
|
|
||||||
|
// Max is 80
|
||||||
|
if ($limit > 80) {
|
||||||
|
$limit = 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fave = $this->fetch_faves($user->getID(), $limit, $since_id, $max_id);
|
||||||
|
|
||||||
|
$faves = array();
|
||||||
|
while ($fave->fetch()) {
|
||||||
|
$faves[] = $this->pretty_fave(clone ($fave));
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = [
|
||||||
|
'@context' => [
|
||||||
|
"https://www.w3.org/ns/activitystreams",
|
||||||
|
[
|
||||||
|
"@language" => "en"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'id' => "{$url}/liked.json",
|
||||||
|
'type' => 'OrderedCollection',
|
||||||
|
'totalItems' => Fave::countByProfile($profile),
|
||||||
|
'orderedItems' => $faves
|
||||||
|
];
|
||||||
|
|
||||||
|
ActivityPubReturn::answer($res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a fave object and turns it in a pretty array to be used
|
||||||
|
* as a plugin answer
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Fave $fave_object
|
||||||
|
* @return array pretty array representating a Fave
|
||||||
|
*/
|
||||||
|
protected function pretty_fave($fave_object)
|
||||||
|
{
|
||||||
|
$res = array("uri" => $fave_object->uri,
|
||||||
|
"created" => $fave_object->created,
|
||||||
|
"object" => Activitypub_notice::notice_to_array(Notice::getByID($fave_object->notice_id)));
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch faves
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param int32 $user_id
|
||||||
|
* @param int32 $limit
|
||||||
|
* @param int32 $since_id
|
||||||
|
* @param int32 $max_id
|
||||||
|
* @return Fave fetchable fave collection
|
||||||
|
*/
|
||||||
|
private static function fetch_faves(
|
||||||
|
$user_id,
|
||||||
|
$limit = 40,
|
||||||
|
$since_id = null,
|
||||||
|
$max_id = null
|
||||||
|
) {
|
||||||
|
$fav = new Fave();
|
||||||
|
|
||||||
|
$fav->user_id = $user_id;
|
||||||
|
|
||||||
|
$fav->orderBy('modified DESC');
|
||||||
|
|
||||||
|
if ($since_id != null) {
|
||||||
|
$fav->whereAdd("notice_id > {$since_id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($max_id != null) {
|
||||||
|
$fav->whereAdd("notice_id < {$max_id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$fav->limit($limit);
|
||||||
|
|
||||||
|
$fav->find();
|
||||||
|
|
||||||
|
return $fav;
|
||||||
|
}
|
||||||
|
}
|
@ -1,149 +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 Liked Collection
|
|
||||||
*
|
|
||||||
* @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 apActorLikedCollectionAction extends ManagedAction
|
|
||||||
{
|
|
||||||
protected $needLogin = false;
|
|
||||||
protected $canPost = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the Liked Collection request
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function handle ()
|
|
||||||
{
|
|
||||||
$nickname = $this->trimmed ('nickname');
|
|
||||||
try {
|
|
||||||
$user = User::getByNickname ($nickname);
|
|
||||||
$profile = $user->getProfile ();
|
|
||||||
$url = $profile->profileurl;
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error ('Invalid username.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$limit = intval ($this->trimmed ('limit'));
|
|
||||||
$since_id = intval ($this->trimmed ('since_id'));
|
|
||||||
$max_id = intval ($this->trimmed ('max_id'));
|
|
||||||
|
|
||||||
$limit = empty ($limit) ? 40 : $limit; // Default is 40
|
|
||||||
$since_id = empty ($since_id) ? null : $since_id;
|
|
||||||
$max_id = empty ($max_id) ? null : $max_id;
|
|
||||||
|
|
||||||
// Max is 80
|
|
||||||
if ($limit > 80) {
|
|
||||||
$limit = 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
$fave = $this->fetch_faves ($user->getID(), $limit, $since_id, $max_id);
|
|
||||||
|
|
||||||
$faves = array ();
|
|
||||||
while ($fave->fetch ()) {
|
|
||||||
$faves[] = $this->pretty_fave (clone ($fave));
|
|
||||||
}
|
|
||||||
|
|
||||||
$res = [
|
|
||||||
'@context' => [
|
|
||||||
"https://www.w3.org/ns/activitystreams",
|
|
||||||
[
|
|
||||||
"@language" => "en"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'id' => "{$url}/liked.json",
|
|
||||||
'type' => 'OrderedCollection',
|
|
||||||
'totalItems' => Fave::countByProfile ($profile),
|
|
||||||
'orderedItems' => $faves
|
|
||||||
];
|
|
||||||
|
|
||||||
ActivityPubReturn::answer ($res);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Take a fave object and turns it in a pretty array to be used
|
|
||||||
* as a plugin answer
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param Fave $fave_object
|
|
||||||
* @return array pretty array representating a Fave
|
|
||||||
*/
|
|
||||||
protected function pretty_fave ($fave_object)
|
|
||||||
{
|
|
||||||
$res = array("uri" => $fave_object->uri,
|
|
||||||
"created" => $fave_object->created,
|
|
||||||
"object" => Activitypub_notice::notice_to_array (Notice::getByID ($fave_object->notice_id)));
|
|
||||||
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch faves
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param int32 $user_id
|
|
||||||
* @param int32 $limit
|
|
||||||
* @param int32 $since_id
|
|
||||||
* @param int32 $max_id
|
|
||||||
* @return Fave fetchable fave collection
|
|
||||||
*/
|
|
||||||
private static function fetch_faves ($user_id, $limit = 40, $since_id = null,
|
|
||||||
$max_id = null)
|
|
||||||
{
|
|
||||||
$fav = new Fave ();
|
|
||||||
|
|
||||||
$fav->user_id = $user_id;
|
|
||||||
|
|
||||||
$fav->orderBy ('modified DESC');
|
|
||||||
|
|
||||||
if ($since_id != null) {
|
|
||||||
$fav->whereAdd ("notice_id > {$since_id}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($max_id != null) {
|
|
||||||
$fav->whereAdd ("notice_id < {$max_id}");
|
|
||||||
}
|
|
||||||
|
|
||||||
$fav->limit ($limit);
|
|
||||||
|
|
||||||
$fav->find ();
|
|
||||||
|
|
||||||
return $fav;
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,14 +19,14 @@
|
|||||||
*
|
*
|
||||||
* @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>
|
||||||
|
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,35 +34,44 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*
|
*
|
||||||
* @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>
|
||||||
* @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 http://www.gnu.org/software/social/
|
* @link http://www.gnu.org/software/social/
|
||||||
*/
|
*/
|
||||||
class apActorProfileAction extends ManagedAction
|
class apActorProfileAction extends ManagedAction
|
||||||
{
|
{
|
||||||
protected $needLogin = false;
|
protected $needLogin = false;
|
||||||
protected $canPost = true;
|
protected $canPost = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the Actor Profile request
|
* Handle the Actor Profile request
|
||||||
*
|
*
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function handle()
|
protected function handle()
|
||||||
{
|
{
|
||||||
$nickname = $this->trimmed ('nickname');
|
if (!empty($id = $this->trimmed('id'))) {
|
||||||
try {
|
try {
|
||||||
$user = User::getByNickname ($nickname);
|
$profile = Profile::getByID($id);
|
||||||
$profile = $user->getProfile ();
|
} catch (Exception $e) {
|
||||||
}
|
ActivityPubReturn::error('Invalid Actor URI.', 404);
|
||||||
catch (Exception $e) {
|
}
|
||||||
ActivityPubReturn::error ('Invalid username.', 404);
|
unset($id);
|
||||||
}
|
} else {
|
||||||
|
try {
|
||||||
$res = Activitypub_profile::profile_to_array ($profile);
|
$profile = User::getByNickname($this->trimmed('nickname'))->getProfile();
|
||||||
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::answer ($res);
|
ActivityPubReturn::error('Invalid username.', 404);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$profile->isLocal()) {
|
||||||
|
ActivityPubReturn::error("This is not a local user.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = Activitypub_profile::profile_to_array($profile);
|
||||||
|
|
||||||
|
ActivityPubReturn::answer($res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
92
actions/apauthorizeremotefollow.php
Normal file
92
actions/apauthorizeremotefollow.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorize Remote Follow
|
||||||
|
*
|
||||||
|
* @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 apAuthorizeRemoteFollowAction extends Action
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Prepare to handle the Authorize Remote Follow request.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param array $args
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function prepare(array $args=array())
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
if (!common_logged_in()) {
|
||||||
|
// XXX: selfURL() didn't work. :<
|
||||||
|
common_set_returnto($_SERVER['REQUEST_URI']);
|
||||||
|
if (Event::handle('RedirectToLogin', array($this, null))) {
|
||||||
|
common_redirect(common_local_url('login'), 303);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (!isset($_GET["acct"])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the Authorize Remote Follow Request.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
*/
|
||||||
|
protected function handle()
|
||||||
|
{
|
||||||
|
$other = Activitypub_profile::get_from_uri($_GET["acct"]);
|
||||||
|
$actor_profile = common_current_user()->getProfile();
|
||||||
|
$object_profile = $other->local_profile();
|
||||||
|
if (!Subscription::exists($actor_profile, $object_profile)) {
|
||||||
|
Subscription::start($actor_profile, $object_profile);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$postman = new Activitypub_postman($actor_profile, [$other]);
|
||||||
|
$postman->follow();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Meh, let the exception go on its merry way, it shouldn't be all
|
||||||
|
// that important really.
|
||||||
|
}
|
||||||
|
common_redirect(common_local_url('userbyid', array('id' => $other->profile_id)), 303);
|
||||||
|
}
|
||||||
|
}
|
239
actions/apremotefollow.php
Normal file
239
actions/apremotefollow.php
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remote Follow
|
||||||
|
*
|
||||||
|
* @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 apRemoteFollowAction extends Action
|
||||||
|
{
|
||||||
|
public $nickname;
|
||||||
|
public $local_profile;
|
||||||
|
public $remote_identifier;
|
||||||
|
public $err;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare to handle the Remote Follow request.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param array $args
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function prepare(array $args=array())
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
if (common_logged_in()) {
|
||||||
|
// TRANS: Client error.
|
||||||
|
$this->clientError(_m('You can use the local subscription!'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local user the remote wants to subscribe to
|
||||||
|
$this->nickname = $this->trimmed('nickname');
|
||||||
|
$this->local_profile = User::getByNickname($this->nickname)->getProfile();
|
||||||
|
|
||||||
|
// Webfinger or profile URL of the remote user
|
||||||
|
$this->remote_identifier = $this->trimmed('remote_identifier');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the Remote Follow Request.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
*/
|
||||||
|
protected function handle()
|
||||||
|
{
|
||||||
|
parent::handle();
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
/* Use a session token for CSRF protection. */
|
||||||
|
$token = $this->trimmed('token');
|
||||||
|
if (!$token || $token != common_session_token()) {
|
||||||
|
// TRANS: Client error displayed when the session token does not match or is not given.
|
||||||
|
$this->showForm(_m('There was a problem with your session token. '.
|
||||||
|
'Try again, please.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->activitypub_connect();
|
||||||
|
} else {
|
||||||
|
$this->showForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form.
|
||||||
|
*
|
||||||
|
* @author GNU Social
|
||||||
|
* @param string|null $err
|
||||||
|
*/
|
||||||
|
public function showForm($err = null)
|
||||||
|
{
|
||||||
|
$this->err = $err;
|
||||||
|
if ($this->boolean('ajax')) {
|
||||||
|
$this->startHTML('text/xml;charset=utf-8');
|
||||||
|
$this->elementStart('head');
|
||||||
|
// TRANS: Form title.
|
||||||
|
$this->element('title', null, _m('TITLE', 'Subscribe to user'));
|
||||||
|
$this->elementEnd('head');
|
||||||
|
$this->elementStart('body');
|
||||||
|
$this->showContent();
|
||||||
|
$this->elementEnd('body');
|
||||||
|
$this->endHTML();
|
||||||
|
} else {
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page content.
|
||||||
|
*
|
||||||
|
* @author GNU Social
|
||||||
|
*/
|
||||||
|
public function showContent()
|
||||||
|
{
|
||||||
|
// TRANS: Form legend. %s is a nickname.
|
||||||
|
$header = sprintf(_m('Subscribe to %s'), $this->nickname);
|
||||||
|
// TRANS: Button text to subscribe to a profile.
|
||||||
|
$submit = _m('BUTTON', 'Subscribe');
|
||||||
|
$this->elementStart(
|
||||||
|
'form',
|
||||||
|
['id' => 'form_activitypub_connect',
|
||||||
|
'method' => 'post',
|
||||||
|
'class' => 'form_settings',
|
||||||
|
'action' => common_local_url(
|
||||||
|
'apRemoteFollow',
|
||||||
|
['nickname' => $this->nickname]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
$this->element('legend', null, $header);
|
||||||
|
$this->hidden('token', common_session_token());
|
||||||
|
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
$this->elementStart('li', array('id' => 'activitypub_nickname'));
|
||||||
|
|
||||||
|
// TRANS: Field label.
|
||||||
|
$this->input(
|
||||||
|
'nickname',
|
||||||
|
_m('User nickname'),
|
||||||
|
$this->nickname,
|
||||||
|
// TRANS: Field title.
|
||||||
|
_m('Nickname of the user you want to follow.')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementStart('li', array('id' => 'activitypub_profile'));
|
||||||
|
// TRANS: Field label.
|
||||||
|
$this->input(
|
||||||
|
'remote_identifier',
|
||||||
|
_m('Profile Account'),
|
||||||
|
$this->remote_identifier,
|
||||||
|
// TRANS: Tooltip for field label "Profile Account".
|
||||||
|
_m('Your account ID (e.g. user@example.net).')
|
||||||
|
);
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
$this->submit('submit', $submit);
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
$this->elementEnd('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start connecting the two instances (will be finished with the authorization)
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function activitypub_connect()
|
||||||
|
{
|
||||||
|
$remote_profile = null;
|
||||||
|
try { // Try with ActivityPub system
|
||||||
|
$remote_profile = Activitypub_profile::get_from_uri($this->remote_identifier);
|
||||||
|
} catch (Exception $e) { // Fallback to compatibility WebFinger system
|
||||||
|
$validate = new Validate();
|
||||||
|
$opts = array('allowed_schemes' => array('http', 'https', 'acct'));
|
||||||
|
if ($validate->uri($this->remote_identifier, $opts)) {
|
||||||
|
$bits = parse_url($this->remote_identifier);
|
||||||
|
if ($bits['scheme'] == 'acct') {
|
||||||
|
$remote_profile = $this->connect_webfinger($bits['path']);
|
||||||
|
}
|
||||||
|
} elseif (strpos($this->remote_identifier, '@') !== false) {
|
||||||
|
$remote_profile = $this->connect_webfinger($this->remote_identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($remote_profile)) {
|
||||||
|
$url = ActivityPubPlugin::stripUrlPath($remote_profile->get_uri())."activitypub/authorize_follow?acct=".$this->local_profile->getUri();
|
||||||
|
common_log(LOG_INFO, "Sending remote subscriber $this->remote_identifier to $url");
|
||||||
|
common_redirect($url, 303);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TRANS: Client error.
|
||||||
|
$this->clientError(_m('Must provide a remote profile.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used by activitypub_connect () and
|
||||||
|
* is a step of the process
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param type $acct
|
||||||
|
* @return Profile Profile resulting of WebFinger connection
|
||||||
|
*/
|
||||||
|
private function connect_webfinger($acct)
|
||||||
|
{
|
||||||
|
$link = ActivityPubPlugin::pull_remote_profile($acct);
|
||||||
|
if (!is_null($link)) {
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
|
// TRANS: Client error.
|
||||||
|
$this->clientError(_m('Could not confirm remote profile address.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page title
|
||||||
|
*
|
||||||
|
* @return string Page title
|
||||||
|
*/
|
||||||
|
public function title()
|
||||||
|
{
|
||||||
|
// TRANS: Page title.
|
||||||
|
return _m('ActivityPub Connect');
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,80 +40,55 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class apSharedInboxAction extends ManagedAction
|
class apSharedInboxAction extends ManagedAction
|
||||||
{
|
{
|
||||||
protected $needLogin = false;
|
protected $needLogin = false;
|
||||||
protected $canPost = true;
|
protected $canPost = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the Shared Inbox request
|
* Handle the Shared Inbox request
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function handle ()
|
protected function handle()
|
||||||
{
|
{
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
ActivityPubReturn::error ("Only POST requests allowed.");
|
ActivityPubReturn::error("Only POST requests allowed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = json_decode (file_get_contents ('php://input'));
|
$data = json_decode(file_get_contents('php://input'));
|
||||||
|
|
||||||
// Validate data
|
// Validate data
|
||||||
if (!isset ($data->type)) {
|
if (!isset($data->type)) {
|
||||||
ActivityPubReturn::error ("Type was not specified.");
|
ActivityPubReturn::error("Type was not specified.");
|
||||||
}
|
}
|
||||||
if (!isset ($data->actor)) {
|
if (!isset($data->actor)) {
|
||||||
ActivityPubReturn::error ("Actor was not specified.");
|
ActivityPubReturn::error("Actor was not specified.");
|
||||||
}
|
}
|
||||||
if (!isset ($data->object)) {
|
if (!isset($data->object)) {
|
||||||
ActivityPubReturn::error ("Object was not specified.");
|
ActivityPubReturn::error("Object was not specified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$discovery = new Activitypub_explorer;
|
$discovery = new Activitypub_explorer;
|
||||||
|
// Get valid Actor object
|
||||||
|
try {
|
||||||
|
$actor_profile = $discovery->lookup($data->actor);
|
||||||
|
$actor_profile = $actor_profile[0];
|
||||||
|
} catch (Exception $e) {
|
||||||
|
ActivityPubReturn::error("Invalid Actor.", 404);
|
||||||
|
}
|
||||||
|
unset($discovery);
|
||||||
|
|
||||||
// Get valid Actor object
|
// Public To:
|
||||||
try {
|
$public_to = ["https://www.w3.org/ns/activitystreams#Public",
|
||||||
$actor_profile = $discovery->lookup ($data->actor);
|
"Public",
|
||||||
$actor_profile = $actor_profile[0];
|
"as:Public"
|
||||||
} catch (Exception $e) {
|
];
|
||||||
ActivityPubReturn::error ("Invalid Actor.", 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
unset ($discovery);
|
$to_profiles = "https://www.w3.org/ns/activitystreams#Public";
|
||||||
|
|
||||||
// Public To:
|
// Process request
|
||||||
$public_to = array ("https://www.w3.org/ns/activitystreams#Public",
|
switch ($data->type) {
|
||||||
"Public",
|
|
||||||
"as:Public");
|
|
||||||
|
|
||||||
// Process request
|
|
||||||
switch ($data->type) {
|
|
||||||
case "Create":
|
case "Create":
|
||||||
if (!isset($data->to)) {
|
|
||||||
ActivityPubReturn::error ("To was not specified.");
|
|
||||||
}
|
|
||||||
$discovery = new Activitypub_explorer;
|
|
||||||
$to_profiles = array ();
|
|
||||||
// Generate To objects
|
|
||||||
if (is_array ($data->to)) {
|
|
||||||
// Remove duplicates from To actors set
|
|
||||||
array_unique ($data->to);
|
|
||||||
foreach ($data->to as $to_url) {
|
|
||||||
try {
|
|
||||||
$to_profiles = array_merge ($to_profiles, $discovery->lookup ($to_url));
|
|
||||||
} catch (Exception $e) {
|
|
||||||
// XXX: Invalid actor found, not sure how we handle those
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (empty ($data->to) || in_array ($data->to, $public_to)) {
|
|
||||||
// No need to do anything else at this point, let's just break out the if
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
$to_profiles[]= $discovery->lookup ($data->to);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
ActivityPubReturn::error ("Invalid Actor.", 404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unset ($discovery);
|
|
||||||
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Create.php";
|
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Create.php";
|
||||||
break;
|
break;
|
||||||
case "Follow":
|
case "Follow":
|
||||||
@ -131,8 +106,14 @@ class apSharedInboxAction extends ManagedAction
|
|||||||
case "Delete":
|
case "Delete":
|
||||||
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Delete.php";
|
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Delete.php";
|
||||||
break;
|
break;
|
||||||
|
case "Accept":
|
||||||
|
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Accept.php";
|
||||||
|
break;
|
||||||
|
case "Reject":
|
||||||
|
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Reject.php";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ActivityPubReturn::error ("Invalid type value.");
|
ActivityPubReturn::error("Invalid type value.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
58
actions/inbox/Accept.php
Normal file
58
actions/inbox/Accept.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?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 "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);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pending_list = new Activitypub_pending_follow_requests($actor_profile->getID(), $object_profile->getID());
|
||||||
|
$pending_list->remove();
|
||||||
|
ActivityPubReturn::answer($data); // You are now being followed by this person.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ActivityPubReturn::error("Invalid object type.");
|
||||||
|
break;
|
||||||
|
}
|
@ -25,13 +25,13 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Notice::getByUri ($data->object)->repeat ($actor_profile, "ActivityPub");
|
Notice::getByUri($data->object->id)->repeat($actor_profile, "ActivityPub");
|
||||||
ActivityPubReturn::answer ("Notice repeated successfully.");
|
ActivityPubReturn::answer("Notice repeated successfully.");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ($e->getMessage (), 403);
|
ActivityPubReturn::error($e->getMessage(), 403);
|
||||||
}
|
}
|
||||||
|
@ -25,79 +25,109 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$valid_object_types = array ("Note");
|
$valid_object_types = array("Note");
|
||||||
|
|
||||||
// Validate data
|
// Validate data
|
||||||
if (!(isset ($data->object->type) && in_array ($data->object->type, $valid_object_types))) {
|
if (!isset($data->id)) {
|
||||||
ActivityPubReturn::error ("Invalid Object type.");
|
ActivityPubReturn::error("Id not specified.");
|
||||||
}
|
}
|
||||||
if (!isset ($data->object->content)) {
|
if (!(isset($data->object->type) && in_array($data->object->type, $valid_object_types))) {
|
||||||
ActivityPubReturn::error ("Object content was not specified.");
|
ActivityPubReturn::error("Invalid Object type.");
|
||||||
}
|
}
|
||||||
if (!isset ($data->object->url)) {
|
if (!isset($data->object->content)) {
|
||||||
ActivityPubReturn::error ("Object url was not specified.");
|
ActivityPubReturn::error("Object content was not specified.");
|
||||||
} else if (!filter_var ($data->object->url, FILTER_VALIDATE_URL)) {
|
}
|
||||||
ActivityPubReturn::error ("Invalid Object Url.");
|
if (!isset($data->object->url)) {
|
||||||
|
ActivityPubReturn::error("Object url was not specified.");
|
||||||
|
} elseif (!filter_var($data->object->url, FILTER_VALIDATE_URL)) {
|
||||||
|
ActivityPubReturn::error("Invalid Object Url.");
|
||||||
|
}
|
||||||
|
if (!isset($data->object->to)) {
|
||||||
|
ActivityPubReturn::error("Object To was not specified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = $data->object->content;
|
$content = $data->object->content;
|
||||||
|
|
||||||
$act = new Activity ();
|
$act = new Activity();
|
||||||
$act->verb = ActivityVerb::POST;
|
$act->verb = ActivityVerb::POST;
|
||||||
$act->time = time ();
|
$act->time = time();
|
||||||
$act->actor = $actor_profile->asActivityObject ();
|
$act->actor = $actor_profile->asActivityObject();
|
||||||
|
|
||||||
$act->context = new ActivityContext ();
|
$act->context = new ActivityContext();
|
||||||
|
|
||||||
// Is this a reply?
|
// Is this a reply?
|
||||||
if (isset ($data->object->reply_to)) {
|
if (isset($data->object->reply_to)) {
|
||||||
try {
|
try {
|
||||||
$reply_to = Notice::getByUri ($data->object->reply_to);
|
$reply_to = Notice::getByUri($data->object->reply_to);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ("Invalid Object reply_to value.");
|
ActivityPubReturn::error("Invalid Object reply_to value.");
|
||||||
}
|
}
|
||||||
$act->context->replyToID = $reply_to->getUri ();
|
$act->context->replyToID = $reply_to->getUri();
|
||||||
$act->context->replyToUrl = $reply_to->getUrl ();
|
$act->context->replyToUrl = $reply_to->getUrl();
|
||||||
} else {
|
} else {
|
||||||
$reply_to = null;
|
$reply_to = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$act->context->attention = common_get_attentions ($content, $actor_profile, $reply_to);
|
$act->context->attention = common_get_attentions($content, $actor_profile, $reply_to);
|
||||||
|
|
||||||
foreach ($to_profiles as $to)
|
$discovery = new Activitypub_explorer;
|
||||||
{
|
if ($to_profiles == "https://www.w3.org/ns/activitystreams#Public") {
|
||||||
$act->context->attention[$to->getUri ()] = "http://activitystrea.ms/schema/1.0/person";
|
$to_profiles = array();
|
||||||
|
}
|
||||||
|
// Generate To objects
|
||||||
|
if (is_array($data->object->to)) {
|
||||||
|
// Remove duplicates from To actors set
|
||||||
|
array_unique($data->object->to);
|
||||||
|
foreach ($data->object->to as $to_url) {
|
||||||
|
try {
|
||||||
|
$to_profiles = array_merge($to_profiles, $discovery->lookup($to_url));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// XXX: Invalid actor found, not sure how we handle those
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (empty($data->object->to) || in_array($data->object->to, $public_to)) {
|
||||||
|
// No need to do anything else at this point, let's just break out the if
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$to_profiles[]= $discovery->lookup($data->object->to);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
ActivityPubReturn::error("Invalid Actor.", 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($discovery);
|
||||||
|
|
||||||
|
foreach ($to_profiles as $to) {
|
||||||
|
$act->context->attention[ActivityPubPlugin::actor_uri($to)] = "http://activitystrea.ms/schema/1.0/person";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject notice if it is too long (without the HTML)
|
// Reject notice if it is too long (without the HTML)
|
||||||
// This is done after MediaFile::fromUpload etc. just to act the same as the ApiStatusesUpdateAction
|
// This is done after MediaFile::fromUpload etc. just to act the same as the ApiStatusesUpdateAction
|
||||||
if (Notice::contentTooLong ($content)) {
|
if (Notice::contentTooLong($content)) {
|
||||||
ActivityPubReturn::error ("That's too long. Maximum notice size is %d character.");
|
ActivityPubReturn::error("That's too long. Maximum notice size is %d character.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$options = array ('source' => 'ActivityPub', 'uri' => $data->id, 'url' => $data->object->url);
|
$options = array('source' => 'ActivityPub', 'uri' => isset($data->id) ? $data->id : $data->object->url, 'url' => $data->object->url);
|
||||||
// $options gets filled with possible scoping settings
|
// $options gets filled with possible scoping settings
|
||||||
ToSelector::fillActivity ($this, $act, $options);
|
ToSelector::fillActivity($this, $act, $options);
|
||||||
|
|
||||||
$actobj = new ActivityObject ();
|
$actobj = new ActivityObject();
|
||||||
$actobj->type = ActivityObject::NOTE;
|
$actobj->type = ActivityObject::NOTE;
|
||||||
$actobj->content = common_render_content ($content, $actor_profile, $reply_to);
|
$actobj->content = common_render_content($content, $actor_profile, $reply_to);
|
||||||
|
|
||||||
// Finally add the activity object to our activity
|
// Finally add the activity object to our activity
|
||||||
$act->objects[] = $actobj;
|
$act->objects[] = $actobj;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$res = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
$res = Activitypub_create::create_to_array(
|
||||||
"id" => $data->id,
|
$data->id,
|
||||||
"url" => $data->object->url,
|
$data->actor,
|
||||||
"type" => "Create",
|
Activitypub_notice::notice_to_array(Notice::saveActivity($act, $actor_profile, $options))
|
||||||
"actor" => $data->actor,
|
);
|
||||||
"object" => Activitypub_notice::notice_to_array (Notice::saveActivity ($act, $actor_profile, $options)));
|
ActivityPubReturn::answer($res);
|
||||||
ActivityPubReturn::answer ($res);
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ($e->getMessage ());
|
ActivityPubReturn::error($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -25,17 +25,15 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Notice::getByUri ($data->object)->deleteAs ($actor_profile);
|
$notice = Notice::getByUri($data->object->id);
|
||||||
$res = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
$notice_to_array = Activitypub_notice::notice_to_array($notice);
|
||||||
"type" => "Delete",
|
$notice->deleteAs($actor_profile);
|
||||||
"actor" => $data->actor,
|
ActivityPubReturn::answer(Activitypub_delete::delete_to_array($notice_to_array));
|
||||||
"object" => $data->object);
|
|
||||||
ActivityPubReturn::answer ($res);
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ($e->getMessage (), 403);
|
ActivityPubReturn::error($e->getMessage(), 403);
|
||||||
}
|
}
|
||||||
|
@ -25,34 +25,30 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate Object
|
// Validate Object
|
||||||
if (!is_string ($data->object)) {
|
if (!is_string($data->object)) {
|
||||||
ActivityPubReturn::error ("Invalid Object object, URL expected.");
|
ActivityPubReturn::error("Invalid Object object, URL expected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get valid Object profile
|
// Get valid Object profile
|
||||||
try {
|
try {
|
||||||
$object_profile = new Activitypub_explorer;
|
$object_profile = new Activitypub_explorer;
|
||||||
$object_profile = $object_profile->lookup ($data->object)[0];
|
$object_profile = $object_profile->lookup($data->object)[0];
|
||||||
} catch(Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ("Invalid Object Actor URL.", 404);
|
ActivityPubReturn::error("Invalid Object Actor URL.", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!Subscription::exists ($actor_profile, $object_profile)) {
|
if (!Subscription::exists($actor_profile, $object_profile)) {
|
||||||
Subscription::start ($actor_profile, $object_profile);
|
Subscription::start($actor_profile, $object_profile);
|
||||||
$res = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
ActivityPubReturn::answer(Activitypub_accept::accept_to_array(Activitypub_follow::follow_to_array($data->actor, $data->object)));
|
||||||
"type" => "Follow",
|
} else {
|
||||||
"actor" => $data->actor,
|
ActivityPubReturn::error("Already following.", 409);
|
||||||
"object" => $data->object);
|
}
|
||||||
ActivityPubReturn::answer ($res);
|
|
||||||
} else {
|
|
||||||
ActivityPubReturn::error ("Already following.", 409);
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ("Invalid Object Actor URL.", 404);
|
ActivityPubReturn::error("Invalid Object Actor URL.", 404);
|
||||||
}
|
}
|
||||||
|
@ -25,17 +25,17 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($data->object->id)) {
|
||||||
|
ActivityPubReturn::error("Id not specified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Fave::addNew ($actor_profile, Notice::getByUri ($data->object));
|
Fave::addNew($actor_profile, Notice::getByUri($data->object->id));
|
||||||
$res = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
ActivityPubReturn::answer(Activitypub_like::like_to_array(Activitypub_notice::notice_to_array($data->actor, json_decode($data->object))));
|
||||||
"type" => "Like",
|
|
||||||
"actor" => $data->actor,
|
|
||||||
"object" => $data->object);
|
|
||||||
ActivityPubReturn::answer ($res);
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ($e->getMessage (), 403);
|
ActivityPubReturn::error($e->getMessage(), 403);
|
||||||
}
|
}
|
||||||
|
32
actions/inbox/Reject.php
Normal file
32
actions/inbox/Reject.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?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
|
@ -25,53 +25,69 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate data
|
// Validate data
|
||||||
if (!isset ($data->type)) {
|
if (!isset($data->type)) {
|
||||||
ActivityPubReturn::error ("Type was not specified.");
|
ActivityPubReturn::error("Type was not specified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($data->object->type) {
|
switch ($data->object->type) {
|
||||||
case "Like":
|
case "Like":
|
||||||
try {
|
try {
|
||||||
// Validate data
|
// Validate data
|
||||||
if (!isset ($data->object->object)) {
|
if (!isset($data->object->object->id)) {
|
||||||
ActivityPubReturn::error ("Object Notice URL was not specified.");
|
ActivityPubReturn::error("Notice ID was not specified.");
|
||||||
}
|
}
|
||||||
Fave::removeEntry ($actor_profile, Notice::getByUri ($data->object->object));
|
Fave::removeEntry($actor_profile, Notice::getByUri($data->object->object->id));
|
||||||
ActivityPubReturn::answer ("Notice disfavorited successfully.");
|
// Notice disfavorited successfully.
|
||||||
|
ActivityPubReturn::answer(
|
||||||
|
Activitypub_undo::undo_to_array(
|
||||||
|
Activitypub_like::like_to_array(
|
||||||
|
Activitypub_notice::notice_to_array(
|
||||||
|
$actor_profile->getUrl(),
|
||||||
|
$data->object->object
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ($e->getMessage (), 403);
|
ActivityPubReturn::error($e->getMessage(), 403);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "Follow":
|
case "Follow":
|
||||||
// Validate data
|
// Validate data
|
||||||
if (!isset ($data->object->object)) {
|
if (!isset($data->object->object)) {
|
||||||
ActivityPubReturn::error ("Object Actor URL was not specified.");
|
ActivityPubReturn::error("Object Actor URL was not specified.");
|
||||||
}
|
}
|
||||||
// Get valid Object profile
|
// Get valid Object profile
|
||||||
try {
|
try {
|
||||||
$object_profile = new Activitypub_explorer;
|
$object_profile = new Activitypub_explorer;
|
||||||
$object_profile = $object_profile->lookup ($data->object->object)[0];
|
$object_profile = $object_profile->lookup($data->object->object)[0];
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
ActivityPubReturn::error ("Invalid Object Actor URL.", 404);
|
ActivityPubReturn::error("Invalid Object Actor URL.", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (Subscription::exists($actor_profile, $object_profile)) {
|
||||||
if (Subscription::exists ($actor_profile, $object_profile)) {
|
Subscription::cancel($actor_profile, $object_profile);
|
||||||
Subscription::cancel ($actor_profile, $object_profile);
|
// You are no longer following this person.
|
||||||
ActivityPubReturn::answer ("You are no longer following this person.");
|
ActivityPubReturn::answer(
|
||||||
} else {
|
Activitypub_undo::undo_to_array(
|
||||||
ActivityPubReturn::error ("You are not following this person already.", 409);
|
Activitypub_accept::accept_to_array(
|
||||||
}
|
Activitypub_follow::follow_to_array(
|
||||||
} catch (Exception $e) {
|
$actor_profile->getUrl(),
|
||||||
ActivityPubReturn::error ("Invalid Object Actor URL.", 404);
|
$object_profile->getUrl()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ActivityPubReturn::error("You are not following this person already.", 409);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ActivityPubReturn::error ("Invalid object type.");
|
ActivityPubReturn::error("Invalid object type.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
58
classes/Activitypub_accept.php
Normal file
58
classes/Activitypub_accept.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?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 error representation
|
||||||
|
*
|
||||||
|
* @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_accept extends Managed_DataObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates an ActivityPub representation of a Accept
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param array $object
|
||||||
|
* @return pretty array to be used in a response
|
||||||
|
*/
|
||||||
|
public static function accept_to_array($object)
|
||||||
|
{
|
||||||
|
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Accept",
|
||||||
|
"object" => $object
|
||||||
|
);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
59
classes/Activitypub_announce.php
Normal file
59
classes/Activitypub_announce.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?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 error representation
|
||||||
|
*
|
||||||
|
* @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_announce extends Managed_DataObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates an ActivityPub representation of a Announce
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param array $object
|
||||||
|
* @return pretty array to be used in a response
|
||||||
|
*/
|
||||||
|
public static function announce_to_array($actor, $object)
|
||||||
|
{
|
||||||
|
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Announce",
|
||||||
|
"actor" => $actor,
|
||||||
|
"object" => $object
|
||||||
|
);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,39 +40,38 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class Activitypub_attachment extends Managed_DataObject
|
class Activitypub_attachment extends Managed_DataObject
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Generates a pretty array from an Attachment object
|
* Generates a pretty array from an Attachment object
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Attachment $attachment
|
* @param Attachment $attachment
|
||||||
* @return pretty array to be used in a response
|
* @return pretty array to be used in a response
|
||||||
*/
|
*/
|
||||||
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",
|
||||||
[
|
[
|
||||||
"@language" => "en"
|
"@language" => "en"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'id' => $attachment->getID (),
|
'id' => $attachment->getID(),
|
||||||
'mimetype' => $attachment->mimetype,
|
'mimetype' => $attachment->mimetype,
|
||||||
'url' => $attachment->getUrl (),
|
'url' => $attachment->getUrl(),
|
||||||
'size' => intval($attachment->size), // $attachment->getSize ()
|
'size' => intval($attachment->size), // $attachment->getSize ()
|
||||||
'title' => $attachment->getTitle (),
|
'title' => $attachment->getTitle(),
|
||||||
'meta' => null
|
'meta' => null
|
||||||
];
|
];
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
if (substr ($res["mimetype"], 0, 5) == "image")
|
if (substr($res["mimetype"], 0, 5) == "image") {
|
||||||
{
|
$res["meta"]= [
|
||||||
$res["meta"]= [
|
|
||||||
'width' => $attachment->width,
|
'width' => $attachment->width,
|
||||||
'height' => $attachment->height
|
'height' => $attachment->height
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
return $res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
61
classes/Activitypub_create.php
Normal file
61
classes/Activitypub_create.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?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 error representation
|
||||||
|
*
|
||||||
|
* @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_create extends Managed_DataObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates an ActivityPub representation of a Create
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param string $actor
|
||||||
|
* @param array $object
|
||||||
|
* @return pretty array to be used in a response
|
||||||
|
*/
|
||||||
|
public static function create_to_array($id, $actor, $object)
|
||||||
|
{
|
||||||
|
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"id" => $id,
|
||||||
|
"type" => "Create",
|
||||||
|
"actor" => $actor,
|
||||||
|
"object" => $object
|
||||||
|
);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
59
classes/Activitypub_delete.php
Normal file
59
classes/Activitypub_delete.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?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 error representation
|
||||||
|
*
|
||||||
|
* @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_delete extends Managed_DataObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates an ActivityPub representation of a Delete
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param array $object
|
||||||
|
* @return pretty array to be used in a response
|
||||||
|
*/
|
||||||
|
public static function delete_to_array($object)
|
||||||
|
{
|
||||||
|
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Delete",
|
||||||
|
"actor" => $object["actor"],
|
||||||
|
"object" => $object
|
||||||
|
);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,18 +40,18 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class Activitypub_error extends Managed_DataObject
|
class Activitypub_error extends Managed_DataObject
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Generates a pretty error from a string
|
* Generates a pretty error from a string
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param string $m
|
* @param string $m
|
||||||
* @return pretty array to be used in a response
|
* @return pretty array to be used in a response
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
60
classes/Activitypub_follow.php
Normal file
60
classes/Activitypub_follow.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?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 error representation
|
||||||
|
*
|
||||||
|
* @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_follow extends Managed_DataObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates an ActivityPub representation of a subscription
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param string $actor
|
||||||
|
* @param string $object
|
||||||
|
* @return pretty array to be used in a response
|
||||||
|
*/
|
||||||
|
public static function follow_to_array($actor, $object)
|
||||||
|
{
|
||||||
|
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Follow",
|
||||||
|
"actor" => $actor,
|
||||||
|
"object" => $object
|
||||||
|
);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
60
classes/Activitypub_like.php
Normal file
60
classes/Activitypub_like.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?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 error representation
|
||||||
|
*
|
||||||
|
* @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_like extends Managed_DataObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates an ActivityPub representation of a Like
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param string $actor
|
||||||
|
* @param array $object
|
||||||
|
* @return pretty array to be used in a response
|
||||||
|
*/
|
||||||
|
public static function like_to_array($actor, $object)
|
||||||
|
{
|
||||||
|
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Like",
|
||||||
|
"actor" => $actor,
|
||||||
|
"object" => $object
|
||||||
|
);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,51 +41,51 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class Activitypub_notice extends Managed_DataObject
|
class Activitypub_notice extends Managed_DataObject
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Generates a pretty notice from a Notice object
|
* Generates a pretty notice from a Notice object
|
||||||
*
|
*
|
||||||
* @author Daniel Supernault <danielsupernault@gmail.com>
|
* @author Daniel Supernault <danielsupernault@gmail.com>
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Notice $notice
|
* @param Notice $notice
|
||||||
* @return pretty array to be used in a response
|
* @return pretty array to be used in a response
|
||||||
*/
|
*/
|
||||||
public static function notice_to_array ($notice)
|
public static function notice_to_array($notice)
|
||||||
{
|
{
|
||||||
$attachments = array ();
|
$attachments = array();
|
||||||
foreach($notice->attachments () as $attachment) {
|
foreach ($notice->attachments() as $attachment) {
|
||||||
$attachments[] = Activitypub_attachment::attachment_to_array ($attachment);
|
$attachments[] = Activitypub_attachment::attachment_to_array($attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
$tags = array ();
|
$tags = array();
|
||||||
foreach($notice->getTags()as $tag) {
|
foreach ($notice->getTags() as $tag) {
|
||||||
if ($tag != "") { // Hacky workaround to avoid stupid outputs
|
if ($tag != "") { // Hacky workaround to avoid stupid outputs
|
||||||
$tags[] = Activitypub_tag::tag_to_array ($tag);
|
$tags[] = Activitypub_tag::tag_to_array($tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$to = array ();
|
$to = array();
|
||||||
foreach ($notice->getAttentionProfileIDs () as $to_id) {
|
foreach ($notice->getAttentionProfiles() as $to_profile) {
|
||||||
$to[] = Profile::getById ($to_id)->getUri ();
|
$to[] = $to_profile->getUri();
|
||||||
}
|
}
|
||||||
if (!is_null($to)) {
|
if (empty($to)) {
|
||||||
$to = array ("https://www.w3.org/ns/activitystreams#Public");
|
$to = array("https://www.w3.org/ns/activitystreams#Public");
|
||||||
}
|
}
|
||||||
|
|
||||||
$item = [
|
$item = [
|
||||||
'id' => $notice->getUrl (),
|
'id' => $notice->getUri(),
|
||||||
'type' => 'Notice',
|
'type' => 'Note',
|
||||||
'actor' => $notice->getProfile ()->getUrl (),
|
'actor' => $notice->getProfile()->getUrl(),
|
||||||
'published' => $notice->getCreated (),
|
'published' => $notice->getCreated(),
|
||||||
'to' => $to,
|
'to' => $to,
|
||||||
'content' => $notice->getContent (),
|
'content' => $notice->getContent(),
|
||||||
'url' => $notice->getUrl (),
|
'url' => $notice->getUrl(),
|
||||||
'reply_to' => empty($notice->reply_to) ? null : Notice::getById($notice->reply_to)->getUrl (),
|
'reply_to' => empty($notice->reply_to) ? null : Notice::getById($notice->reply_to)->getUri(),
|
||||||
'is_local' => $notice->isLocal (),
|
'is_local' => $notice->isLocal(),
|
||||||
'conversation' => intval ($notice->conversation),
|
'conversation' => intval($notice->conversation),
|
||||||
'attachment' => $attachments,
|
'attachment' => $attachments,
|
||||||
'tag' => $tags
|
'tag' => $tags
|
||||||
];
|
];
|
||||||
|
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
105
classes/Activitypub_pending_follow_requests.php
Normal file
105
classes/Activitypub_pending_follow_requests.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?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's Pending follow requests
|
||||||
|
*
|
||||||
|
* @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_pending_follow_requests extends Managed_DataObject
|
||||||
|
{
|
||||||
|
public $__table = 'Activitypub_pending_follow_requests';
|
||||||
|
public $local_profile_id;
|
||||||
|
public $remote_profile_id;
|
||||||
|
private $_reldb = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return table definition for Schema setup and DB_DataObject usage.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @return array array of column definitions
|
||||||
|
*/
|
||||||
|
public static function schemaDef()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'fields' => array(
|
||||||
|
'local_profile_id' => array('type' => 'integer', 'not null' => true),
|
||||||
|
'remote_profile_id' => array('type' => 'integer', 'not null' => true),
|
||||||
|
'relation_id' => array('type' => 'serial', 'not null' => true),
|
||||||
|
),
|
||||||
|
'primary key' => array('relation_id'),
|
||||||
|
'unique keys' => array(
|
||||||
|
'Activitypub_pending_follow_requests_relation_id_key' => array('relation_id'),
|
||||||
|
),
|
||||||
|
'foreign keys' => array(
|
||||||
|
'Activitypub_pending_follow_requests_local_profile_id_fkey' => array('profile', array('local_profile_id' => 'id')),
|
||||||
|
'Activitypub_pending_follow_requests_remote_profile_id_fkey' => array('profile', array('remote_profile_id' => 'id')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct($actor, $remote_actor)
|
||||||
|
{
|
||||||
|
$this->local_profile_id = $actor;
|
||||||
|
$this->remote_profile_id = $remote_actor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Follow request to table.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro
|
||||||
|
* @param int32 $actor actor id
|
||||||
|
* @param int32 $remote_actor remote actor id
|
||||||
|
*/
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
return !$this->exists() && $this->insert();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exists()
|
||||||
|
{
|
||||||
|
$this->_reldb = clone ($this);
|
||||||
|
if ($this->_reldb->find() > 0) {
|
||||||
|
$this->_reldb->fetch();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove()
|
||||||
|
{
|
||||||
|
return $this->exists() && $this->_reldb->delete();
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,331 +35,337 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
* @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>
|
|
||||||
* @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 http://www.gnu.org/software/social/
|
* @link http://www.gnu.org/software/social/
|
||||||
*/
|
*/
|
||||||
class Activitypub_profile extends Profile
|
class Activitypub_profile extends Profile
|
||||||
{
|
{
|
||||||
public $__table = 'Activitypub_profile';
|
public $__table = 'Activitypub_profile';
|
||||||
|
|
||||||
protected $_profile = null;
|
protected $_profile = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return table definition for Schema setup and DB_DataObject usage.
|
* Return table definition for Schema setup and DB_DataObject usage.
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @return array array of column definitions
|
* @return array array of column definitions
|
||||||
*/
|
*/
|
||||||
static function schemaDef ()
|
public static function schemaDef()
|
||||||
{
|
{
|
||||||
return array (
|
return array(
|
||||||
'fields' => array (
|
'fields' => array(
|
||||||
'uri' => array ('type' => 'varchar', 'length' => 191, 'not null' => true),
|
'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true),
|
||||||
'profile_id' => array ('type' => 'integer'),
|
'profile_id' => array('type' => 'integer'),
|
||||||
'inboxuri' => array ('type' => 'varchar', 'length' => 191),
|
'inboxuri' => array('type' => 'varchar', 'length' => 191),
|
||||||
'sharedInboxuri' => array ('type' => 'varchar', 'length' => 191),
|
'sharedInboxuri' => array('type' => 'varchar', 'length' => 191),
|
||||||
'created' => array ('type' => 'datetime', 'not null' => true),
|
'created' => array('type' => 'datetime', 'not null' => true),
|
||||||
'modified' => array ('type' => 'datetime', 'not null' => true),
|
'modified' => array('type' => 'datetime', 'not null' => true),
|
||||||
),
|
),
|
||||||
'primary key' => array ('uri'),
|
'primary key' => array('uri'),
|
||||||
'unique keys' => array (
|
'unique keys' => array(
|
||||||
'Activitypub_profile_profile_id_key' => array ('profile_id'),
|
'Activitypub_profile_profile_id_key' => array('profile_id'),
|
||||||
'Activitypub_profile_inboxuri_key' => array ('inboxuri'),
|
'Activitypub_profile_inboxuri_key' => array('inboxuri'),
|
||||||
),
|
),
|
||||||
'foreign keys' => array (
|
'foreign keys' => array(
|
||||||
'Activitypub_profile_profile_id_fkey' => array ('profile', array ('profile_id' => 'id')),
|
'Activitypub_profile_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a pretty profile from a Profile object
|
* Generates a pretty profile from a Profile object
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Profile $profile
|
* @param Profile $profile
|
||||||
* @return pretty array to be used in a response
|
* @return pretty array to be used in a response
|
||||||
*/
|
*/
|
||||||
public static function profile_to_array ($profile)
|
public static function profile_to_array($profile)
|
||||||
{
|
{
|
||||||
$url = $profile->getURL ();
|
$uri = ActivityPubPlugin::actor_uri($profile);
|
||||||
$res = [
|
$id = $profile->getID();
|
||||||
|
$res = [
|
||||||
'@context' => [
|
'@context' => [
|
||||||
"https://www.w3.org/ns/activitystreams",
|
"https://www.w3.org/ns/activitystreams",
|
||||||
[
|
[
|
||||||
"@language" => "en"
|
"@language" => "en"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'id' => $profile->getID (),
|
'id' => $uri,
|
||||||
'type' => 'Person',
|
'type' => 'Person',
|
||||||
'nickname' => $profile->getNickname (),
|
'preferredUsername' => $profile->getNickname(),
|
||||||
'is_local' => $profile->isLocal (),
|
'is_local' => $profile->isLocal(),
|
||||||
'inbox' => "{$url}/inbox.json",
|
'inbox' => common_local_url("apActorInbox", array("id" => $id)),
|
||||||
'sharedInbox' => common_root_url ()."inbox.json",
|
'name' => $profile->getFullname(),
|
||||||
'outbox' => "{$url}/outbox.json",
|
'followers' => common_local_url("apActorFollowers", array("id" => $id)),
|
||||||
'display_name' => $profile->getFullname (),
|
'followers_count' => $profile->subscriberCount(),
|
||||||
'followers' => "{$url}/followers.json",
|
'following' => common_local_url("apActorFollowing", array("id" => $id)),
|
||||||
'followers_count' => $profile->subscriberCount (),
|
'following_count' => $profile->subscriptionCount(),
|
||||||
'following' => "{$url}/following.json",
|
'liked' => common_local_url("apActorLiked", array("id" => $id)),
|
||||||
'following_count' => $profile->subscriptionCount (),
|
'liked_count' => Fave::countByProfile($profile),
|
||||||
'liked' => "{$url}/liked.json",
|
'summary' => ($desc = $profile->getDescription()) == null ? "" : $desc,
|
||||||
'liked_count' => Fave::countByProfile ($profile),
|
'icon' => [
|
||||||
'summary' => ($desc = $profile->getDescription ()) == null ? "" : $desc,
|
|
||||||
'url' => $profile->getURL (),
|
|
||||||
'avatar' => [
|
|
||||||
'type' => 'Image',
|
'type' => 'Image',
|
||||||
'width' => 96,
|
'width' => AVATAR_PROFILE_SIZE,
|
||||||
'height' => 96,
|
'height' => AVATAR_PROFILE_SIZE,
|
||||||
'url' => $profile->avatarUrl (AVATAR_PROFILE_SIZE)
|
'url' => $profile->avatarUrl(AVATAR_PROFILE_SIZE)
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
return $res;
|
|
||||||
|
if ($profile->isLocal()) {
|
||||||
|
$res["sharedInbox"] = common_local_url("apSharedInbox", array("id" => $id));
|
||||||
|
} else {
|
||||||
|
$aprofile = new Activitypub_profile();
|
||||||
|
$aprofile = $aprofile->from_profile($profile);
|
||||||
|
$res["sharedInbox"] = $aprofile->sharedInboxuri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return $res;
|
||||||
* Insert the current objects variables into the database
|
}
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @access public
|
|
||||||
* @throws ServerException
|
|
||||||
*/
|
|
||||||
public function do_insert ()
|
|
||||||
{
|
|
||||||
$profile = new Profile ();
|
|
||||||
|
|
||||||
$profile->created = $this->created = $this->modified = common_sql_now ();
|
/**
|
||||||
|
* Insert the current objects variables into the database
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @access public
|
||||||
|
* @throws ServerException
|
||||||
|
*/
|
||||||
|
public function do_insert()
|
||||||
|
{
|
||||||
|
$profile = new Profile();
|
||||||
|
|
||||||
$fields = array (
|
$profile->created = $this->created = $this->modified = common_sql_now();
|
||||||
'uri' => 'profileurl',
|
|
||||||
'nickname' => 'nickname',
|
|
||||||
'fullname' => 'fullname',
|
|
||||||
'bio' => 'bio'
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($fields as $af => $pf) {
|
$fields = [
|
||||||
$profile->$pf = $this->$af;
|
'uri' => 'profileurl',
|
||||||
}
|
'nickname' => 'nickname',
|
||||||
|
'fullname' => 'fullname',
|
||||||
|
'bio' => 'bio'
|
||||||
|
];
|
||||||
|
|
||||||
$this->profile_id = $profile->insert ();
|
foreach ($fields as $af => $pf) {
|
||||||
if ($this->profile_id === false) {
|
$profile->$pf = $this->$af;
|
||||||
$profile->query ('ROLLBACK');
|
|
||||||
throw new ServerException ('Profile insertion failed.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$ok = $this->insert ();
|
|
||||||
|
|
||||||
if ($ok === false) {
|
|
||||||
$profile->query ('ROLLBACK');
|
|
||||||
throw new ServerException ('Cannot save ActivityPub profile.');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$this->profile_id = $profile->insert();
|
||||||
* Fetch the locally stored profile for this Activitypub_profile
|
if ($this->profile_id === false) {
|
||||||
*
|
$profile->query('ROLLBACK');
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
throw new ServerException('Profile insertion failed.');
|
||||||
* @return Profile
|
|
||||||
* @throws NoProfileException if it was not found
|
|
||||||
*/
|
|
||||||
public function local_profile ()
|
|
||||||
{
|
|
||||||
$profile = Profile::getKV ('id', $this->profile_id);
|
|
||||||
if (!$profile instanceof Profile) {
|
|
||||||
throw new NoProfileException ($this->profile_id);
|
|
||||||
}
|
|
||||||
return $profile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$ok = $this->insert();
|
||||||
* Generates an Activitypub_profile from a Profile
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param Profile $profile
|
|
||||||
* @return Activitypub_profile
|
|
||||||
* @throws Exception if no Activitypub_profile exists for given Profile
|
|
||||||
*/
|
|
||||||
static function from_profile (Profile $profile)
|
|
||||||
{
|
|
||||||
$profile_id = $profile->getID ();
|
|
||||||
|
|
||||||
$aprofile = self::getKV ('profile_id', $profile_id);
|
if ($ok === false) {
|
||||||
if (!$aprofile instanceof Activitypub_profile) {
|
$profile->query('ROLLBACK');
|
||||||
// No Activitypub_profile for this profile_id,
|
throw new ServerException('Cannot save ActivityPub profile.');
|
||||||
if (!$profile->isLocal ()) {
|
}
|
||||||
// create one!
|
}
|
||||||
$aprofile = self::create_from_local_profile ($profile);
|
|
||||||
} else {
|
|
||||||
throw new Exception ('No Activitypub_profile for Profile ID: '.$profile_id. ', this is a local user.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($profile as $key => $value) {
|
/**
|
||||||
$aprofile->$key = $value;
|
* Fetch the locally stored profile for this Activitypub_profile
|
||||||
}
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @return Profile
|
||||||
|
* @throws NoProfileException if it was not found
|
||||||
|
*/
|
||||||
|
public function local_profile()
|
||||||
|
{
|
||||||
|
$profile = Profile::getKV('id', $this->profile_id);
|
||||||
|
if (!$profile instanceof Profile) {
|
||||||
|
throw new NoProfileException($this->profile_id);
|
||||||
|
}
|
||||||
|
return $profile;
|
||||||
|
}
|
||||||
|
|
||||||
return $aprofile;
|
/**
|
||||||
|
* Generates an Activitypub_profile from a Profile
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Profile $profile
|
||||||
|
* @return Activitypub_profile
|
||||||
|
* @throws Exception if no Activitypub_profile exists for given Profile
|
||||||
|
*/
|
||||||
|
public static function from_profile(Profile $profile)
|
||||||
|
{
|
||||||
|
$profile_id = $profile->getID();
|
||||||
|
|
||||||
|
$aprofile = self::getKV('profile_id', $profile_id);
|
||||||
|
if (!$aprofile instanceof Activitypub_profile) {
|
||||||
|
// No Activitypub_profile for this profile_id,
|
||||||
|
if (!$profile->isLocal()) {
|
||||||
|
// create one!
|
||||||
|
$aprofile = self::create_from_local_profile($profile);
|
||||||
|
} else {
|
||||||
|
throw new Exception('No Activitypub_profile for Profile ID: '.$profile_id. ', this is a local user.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
foreach ($profile as $key => $value) {
|
||||||
* Given an existent local profile creates an ActivityPub profile.
|
$aprofile->$key = $value;
|
||||||
* One must be careful not to give a user profile to this function
|
|
||||||
* as only remote users have ActivityPub_profiles on local instance
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param Profile $profile
|
|
||||||
* @return Activitypub_profile
|
|
||||||
*/
|
|
||||||
private static function create_from_local_profile (Profile $profile)
|
|
||||||
{
|
|
||||||
$url = $profile->getURL ();
|
|
||||||
$inboxes = Activitypub_explorer::get_actor_inboxes_uri ($url);
|
|
||||||
|
|
||||||
$aprofile->created = $aprofile->modified = common_sql_now ();
|
|
||||||
|
|
||||||
$aprofile = new Activitypub_profile;
|
|
||||||
$aprofile->profile_id = $profile->getID ();
|
|
||||||
$aprofile->uri = $url;
|
|
||||||
$aprofile->nickname = $profile->getNickname ();
|
|
||||||
$aprofile->fullname = $profile->getFullname ();
|
|
||||||
$aprofile->bio = substr ($profile->getDescription (), 0, 1000);
|
|
||||||
$aprofile->inboxuri = $inboxes["inbox"];
|
|
||||||
$aprofile->sharedInboxuri = $inboxes["sharedInbox"];
|
|
||||||
|
|
||||||
$aprofile->insert ();
|
|
||||||
|
|
||||||
return $aprofile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return $aprofile;
|
||||||
* Returns sharedInbox if possible, inbox otherwise
|
}
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @return string Inbox URL
|
|
||||||
*/
|
|
||||||
public function get_inbox ()
|
|
||||||
{
|
|
||||||
if (is_null ($this->sharedInboxuri)) {
|
|
||||||
return $this->inboxuri;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->sharedInboxuri;
|
/**
|
||||||
|
* Given an existent local profile creates an ActivityPub profile.
|
||||||
|
* One must be careful not to give a user profile to this function
|
||||||
|
* as only remote users have ActivityPub_profiles on local instance
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Profile $profile
|
||||||
|
* @return Activitypub_profile
|
||||||
|
*/
|
||||||
|
private static function create_from_local_profile(Profile $profile)
|
||||||
|
{
|
||||||
|
$url = $profile->getURL();
|
||||||
|
$inboxes = Activitypub_explorer::get_actor_inboxes_uri($url);
|
||||||
|
|
||||||
|
$aprofile->created = $aprofile->modified = common_sql_now();
|
||||||
|
|
||||||
|
$aprofile = new Activitypub_profile;
|
||||||
|
$aprofile->profile_id = $profile->getID();
|
||||||
|
$aprofile->uri = $url;
|
||||||
|
$aprofile->nickname = $profile->getNickname();
|
||||||
|
$aprofile->fullname = $profile->getFullname();
|
||||||
|
$aprofile->bio = substr($profile->getDescription(), 0, 1000);
|
||||||
|
$aprofile->inboxuri = $inboxes["inbox"];
|
||||||
|
$aprofile->sharedInboxuri = $inboxes["sharedInbox"];
|
||||||
|
|
||||||
|
$aprofile->insert();
|
||||||
|
|
||||||
|
return $aprofile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns sharedInbox if possible, inbox otherwise
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @return string Inbox URL
|
||||||
|
*/
|
||||||
|
public function get_inbox()
|
||||||
|
{
|
||||||
|
if (is_null($this->sharedInboxuri)) {
|
||||||
|
return $this->inboxuri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return $this->sharedInboxuri;
|
||||||
* Getter for uri property
|
}
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
/**
|
||||||
* @return string URI
|
* Getter for uri property
|
||||||
*/
|
*
|
||||||
public function get_uri ()
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
{
|
* @return string URI
|
||||||
return $this->uri;
|
*/
|
||||||
|
public function get_uri()
|
||||||
|
{
|
||||||
|
return $this->uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures a valid Activitypub_profile when provided with a valid URI.
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param string $url
|
||||||
|
* @return Activitypub_profile
|
||||||
|
* @throws Exception if it isn't possible to return an Activitypub_profile
|
||||||
|
*/
|
||||||
|
public static function get_from_uri($url)
|
||||||
|
{
|
||||||
|
$explorer = new Activitypub_explorer();
|
||||||
|
$profiles_found = $explorer->lookup($url);
|
||||||
|
if (!empty($profiles_found)) {
|
||||||
|
return self::from_profile($profiles_found[0]);
|
||||||
|
} else {
|
||||||
|
throw new Exception('No valid ActivityPub profile found for given URI.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up, and if necessary create, an Activitypub_profile for the remote
|
||||||
|
* entity with the given webfinger address.
|
||||||
|
* This should never return null -- you will either get an object or
|
||||||
|
* an exception will be thrown.
|
||||||
|
*
|
||||||
|
* @author GNU Social
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param string $addr webfinger address
|
||||||
|
* @return Activitypub_profile
|
||||||
|
* @throws Exception on error conditions
|
||||||
|
*/
|
||||||
|
public static function ensure_web_finger($addr)
|
||||||
|
{
|
||||||
|
// Normalize $addr, i.e. add 'acct:' if missing
|
||||||
|
$addr = Discovery::normalize($addr);
|
||||||
|
|
||||||
|
// Try the cache
|
||||||
|
$uri = self::cacheGet(sprintf('activitypub_profile:webfinger:%s', $addr));
|
||||||
|
|
||||||
|
if ($uri !== false) {
|
||||||
|
if (is_null($uri)) {
|
||||||
|
// Negative cache entry
|
||||||
|
// TRANS: Exception.
|
||||||
|
throw new Exception(_m('Not a valid webfinger address (via cache).'));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return self::get_from_uri($uri);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_log(LOG_ERR, sprintf(__METHOD__ . ': Webfinger address cache inconsistent with database, did not find Activitypub_profile uri==%s', $uri));
|
||||||
|
self::cacheSet(sprintf('activitypub_profile:webfinger:%s', $addr), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Now, try some discovery
|
||||||
* Ensures a valid Activitypub_profile when provided with a valid URI.
|
|
||||||
*
|
$disco = new Discovery();
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param string $url
|
try {
|
||||||
* @return Activitypub_profile
|
$xrd = $disco->lookup($addr);
|
||||||
* @throws Exception if it isn't possible to return an Activitypub_profile
|
} catch (Exception $e) {
|
||||||
*/
|
// Save negative cache entry so we don't waste time looking it up again.
|
||||||
public static function get_from_uri ($url)
|
// @todo FIXME: Distinguish temporary failures?
|
||||||
{
|
self::cacheSet(sprintf('activitypub_profile:webfinger:%s', $addr), null);
|
||||||
$explorer = new Activitypub_explorer ();
|
// TRANS: Exception.
|
||||||
$profiles_found = $explorer->lookup ($url);
|
throw new Exception(_m('Not a valid webfinger address.'));
|
||||||
if (!empty ($profiles_found)) {
|
|
||||||
return self::from_profile ($profiles_found[0]);
|
|
||||||
} else {
|
|
||||||
throw new Exception ('No valid ActivityPub profile found for given URI');
|
|
||||||
}
|
|
||||||
// If it doesn't return a valid Activitypub_profile an exception will
|
|
||||||
// have been thrown before getting to this point.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$hints = array_merge(
|
||||||
* Look up, and if necessary create, an Activitypub_profile for the remote
|
array('webfinger' => $addr),
|
||||||
* entity with the given webfinger address.
|
DiscoveryHints::fromXRD($xrd)
|
||||||
* This should never return null -- you will either get an object or
|
);
|
||||||
* an exception will be thrown.
|
|
||||||
*
|
|
||||||
* @author GNU Social
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param string $addr webfinger address
|
|
||||||
* @return Activitypub_profile
|
|
||||||
* @throws Exception on error conditions
|
|
||||||
*/
|
|
||||||
public static function ensure_web_finger ($addr)
|
|
||||||
{
|
|
||||||
// Normalize $addr, i.e. add 'acct:' if missing
|
|
||||||
$addr = Discovery::normalize ($addr);
|
|
||||||
|
|
||||||
// Try the cache
|
// If there's an Hcard, let's grab its info
|
||||||
$uri = self::cacheGet (sprintf ('activitypub_profile:webfinger:%s', $addr));
|
if (array_key_exists('hcard', $hints)) {
|
||||||
|
if (!array_key_exists('profileurl', $hints) ||
|
||||||
if ($uri !== false) {
|
|
||||||
if (is_null ($uri)) {
|
|
||||||
// Negative cache entry
|
|
||||||
// TRANS: Exception.
|
|
||||||
throw new Exception (_m ('Not a valid webfinger address (via cache).'));
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return self::get_from_uri ($uri);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
common_log (LOG_ERR, sprintf (__METHOD__ . ': Webfinger address cache inconsistent with database, did not find Activitypub_profile uri==%s', $uri));
|
|
||||||
self::cacheSet (sprintf ('activitypub_profile:webfinger:%s', $addr), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, try some discovery
|
|
||||||
|
|
||||||
$disco = new Discovery ();
|
|
||||||
|
|
||||||
try {
|
|
||||||
$xrd = $disco->lookup ($addr);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
// Save negative cache entry so we don't waste time looking it up again.
|
|
||||||
// @todo FIXME: Distinguish temporary failures?
|
|
||||||
self::cacheSet (sprintf ('activitypub_profile:webfinger:%s', $addr), null);
|
|
||||||
// TRANS: Exception.
|
|
||||||
throw new Exception (_m ('Not a valid webfinger address.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$hints = array_merge (array ('webfinger' => $addr),
|
|
||||||
DiscoveryHints::fromXRD ($xrd));
|
|
||||||
|
|
||||||
// If there's an Hcard, let's grab its info
|
|
||||||
if (array_key_exists ('hcard', $hints)) {
|
|
||||||
if (!array_key_exists ('profileurl', $hints) ||
|
|
||||||
$hints['hcard'] != $hints['profileurl']) {
|
$hints['hcard'] != $hints['profileurl']) {
|
||||||
$hcardHints = DiscoveryHints::fromHcardUrl ($hints['hcard']);
|
$hcardHints = DiscoveryHints::fromHcardUrl($hints['hcard']);
|
||||||
$hints = array_merge ($hcardHints, $hints);
|
$hints = array_merge($hcardHints, $hints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we got a profile page, try that!
|
// If we got a profile page, try that!
|
||||||
$profileUrl = null;
|
$profileUrl = null;
|
||||||
if (array_key_exists ('profileurl', $hints)) {
|
if (array_key_exists('profileurl', $hints)) {
|
||||||
$profileUrl = $hints['profileurl'];
|
$profileUrl = $hints['profileurl'];
|
||||||
try {
|
try {
|
||||||
common_log (LOG_INFO, "Discovery on acct:$addr with profile URL $profileUrl");
|
common_log(LOG_INFO, "Discovery on acct:$addr with profile URL $profileUrl");
|
||||||
$aprofile = self::get_from_uri ($hints['profileurl']);
|
$aprofile = self::get_from_uri($hints['profileurl']);
|
||||||
self::cacheSet (sprintf ('activitypub_profile:webfinger:%s', $addr), $aprofile->get_uri ());
|
self::cacheSet(sprintf('activitypub_profile:webfinger:%s', $addr), $aprofile->get_uri());
|
||||||
return $aprofile;
|
return $aprofile;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
common_log (LOG_WARNING, "Failed creating profile from profile URL '$profileUrl': " . $e->getMessage ());
|
common_log(LOG_WARNING, "Failed creating profile from profile URL '$profileUrl': " . $e->getMessage());
|
||||||
// keep looking
|
// keep looking
|
||||||
//
|
//
|
||||||
// @todo FIXME: This means an error discovering from profile page
|
// @todo FIXME: This means an error discovering from profile page
|
||||||
// may give us a corrupt entry using the webfinger URI, which
|
// may give us a corrupt entry using the webfinger URI, which
|
||||||
// will obscure the correct page-keyed profile later on.
|
// will obscure the correct page-keyed profile later on.
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: try hcard
|
|
||||||
// XXX: try FOAF
|
|
||||||
|
|
||||||
// TRANS: Exception. %s is a webfinger address.
|
|
||||||
throw new Exception (sprintf (_m ('Could not find a valid profile for "%s".'), $addr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX: try hcard
|
||||||
|
// XXX: try FOAF
|
||||||
|
|
||||||
|
// TRANS: Exception. %s is a webfinger address.
|
||||||
|
throw new Exception(sprintf(_m('Could not find a valid profile for "%s".'), $addr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
58
classes/Activitypub_reject.php
Normal file
58
classes/Activitypub_reject.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?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 error representation
|
||||||
|
*
|
||||||
|
* @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_reject extends Managed_DataObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates an ActivityPub representation of a Reject
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param array $object
|
||||||
|
* @return pretty array to be used in a response
|
||||||
|
*/
|
||||||
|
public static function reject_to_array($object)
|
||||||
|
{
|
||||||
|
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Reject",
|
||||||
|
"object" => $object
|
||||||
|
);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,16 +40,16 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class Activitypub_tag extends Managed_DataObject
|
class Activitypub_tag extends Managed_DataObject
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Generates a pretty tag from a Tag object
|
* Generates a pretty tag from a Tag object
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Tag $tag
|
* @param Tag $tag
|
||||||
* @return pretty array to be used in a response
|
* @return pretty array to be used in a response
|
||||||
*/
|
*/
|
||||||
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",
|
||||||
[
|
[
|
||||||
@ -57,9 +57,9 @@ class Activitypub_tag extends Managed_DataObject
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
'name' => $tag,
|
'name' => $tag,
|
||||||
'url' => common_local_url ('tag', array('tag' => $tag))
|
'url' => common_local_url('tag', array('tag' => $tag))
|
||||||
];
|
];
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
classes/Activitypub_undo.php
Normal file
59
classes/Activitypub_undo.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?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 error representation
|
||||||
|
*
|
||||||
|
* @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_undo extends Managed_DataObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generates an ActivityPub representation of a Undo
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param array $object
|
||||||
|
* @return pretty array to be used in a response
|
||||||
|
*/
|
||||||
|
public static function undo_to_array($object)
|
||||||
|
{
|
||||||
|
$res = array("@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Undo",
|
||||||
|
"actor" => $object["actor"],
|
||||||
|
"object" => $object
|
||||||
|
);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
25
composer.json
Normal file
25
composer.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "dansup/activity-pub",
|
||||||
|
"description": "ActivityPub plugin for GNU/Social",
|
||||||
|
"type": "gnusocial-plugin",
|
||||||
|
"require": {},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7.2"
|
||||||
|
},
|
||||||
|
"license": "AGPL",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Daniel Supernault",
|
||||||
|
"email": "danielsupernault@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Diogo Cordeiro",
|
||||||
|
"email": "diogo@fc.up.pt"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1423
composer.lock
generated
Normal file
1423
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
phpunit.xml
Normal file
25
phpunit.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit backupGlobals="false"
|
||||||
|
backupStaticAttributes="false"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
colors="true"
|
||||||
|
convertErrorsToExceptions="true"
|
||||||
|
convertNoticesToExceptions="true"
|
||||||
|
convertWarningsToExceptions="true"
|
||||||
|
processIsolation="false"
|
||||||
|
stopOnFailure="false">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="Feature">
|
||||||
|
<directory suffix="Test.php">./tests/Feature</directory>
|
||||||
|
</testsuite>
|
||||||
|
|
||||||
|
<testsuite name="Unit">
|
||||||
|
<directory suffix="Test.php">./tests/Unit</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
<filter>
|
||||||
|
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||||
|
<directory suffix=".php">./app</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
28
tests/CreatesApplication.php
Normal file
28
tests/CreatesApplication.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests;
|
||||||
|
|
||||||
|
trait CreatesApplication
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates the application.
|
||||||
|
*
|
||||||
|
* @return todo
|
||||||
|
*/
|
||||||
|
public static function createApplication()
|
||||||
|
{
|
||||||
|
if (!defined('INSTALLDIR')) {
|
||||||
|
define('INSTALLDIR', __DIR__ . '/../../../');
|
||||||
|
}
|
||||||
|
if (!defined('GNUSOCIAL')) {
|
||||||
|
define('GNUSOCIAL', true);
|
||||||
|
}
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
define('STATUSNET', true); // compatibility
|
||||||
|
}
|
||||||
|
|
||||||
|
require INSTALLDIR . '/lib/common.php';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
15
tests/TestCase.php
Normal file
15
tests/TestCase.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase as BaseTestCase;
|
||||||
|
|
||||||
|
abstract class TestCase extends BaseTestCase
|
||||||
|
{
|
||||||
|
use CreatesApplication;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->createApplication();
|
||||||
|
}
|
||||||
|
}
|
18
tests/Unit/ExampleTest.php
Normal file
18
tests/Unit/ExampleTest.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class ExampleTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A basic test example.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testBasicTest()
|
||||||
|
{
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
29
tests/Unit/ProfileObjectTest.php
Normal file
29
tests/Unit/ProfileObjectTest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class ProfileObjectTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testLibraryInstalled()
|
||||||
|
{
|
||||||
|
$this->assertTrue(class_exists('\Activitypub_profile'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProfileObject()
|
||||||
|
{
|
||||||
|
// Mimic proper ACCEPT header
|
||||||
|
$_SERVER['HTTP_ACCEPT'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams';
|
||||||
|
|
||||||
|
// Fetch profile
|
||||||
|
$user = \Profile::getKV('id', 1);
|
||||||
|
// Fetch ActivityPub Actor Object representation
|
||||||
|
$profile = \Activitypub_profile::profile_to_array($user);
|
||||||
|
|
||||||
|
$this->assertTrue(is_array($profile));
|
||||||
|
|
||||||
|
$this->assertTrue(isset($profile['inbox']));
|
||||||
|
$this->assertTrue(isset($profile['outbox']));
|
||||||
|
}
|
||||||
|
}
|
@ -24,12 +24,13 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
class DiscoveryHints {
|
class DiscoveryHints
|
||||||
static function fromXRD(XML_XRD $xrd)
|
{
|
||||||
|
public static function fromXRD(XML_XRD $xrd)
|
||||||
{
|
{
|
||||||
$hints = array();
|
$hints = array();
|
||||||
|
|
||||||
@ -60,7 +61,7 @@ class DiscoveryHints {
|
|||||||
return $hints;
|
return $hints;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function fromHcardUrl($url)
|
public static function fromHcardUrl($url)
|
||||||
{
|
{
|
||||||
$client = new HTTPClient();
|
$client = new HTTPClient();
|
||||||
$client->setHeader('Accept', 'text/html,application/xhtml+xml');
|
$client->setHeader('Accept', 'text/html,application/xhtml+xml');
|
||||||
@ -76,11 +77,13 @@ class DiscoveryHints {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::hcardHints($response->getBody(),
|
return self::hcardHints(
|
||||||
$response->getEffectiveUrl());
|
$response->getBody(),
|
||||||
|
$response->getEffectiveUrl()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function hcardHints($body, $url)
|
public static function hcardHints($body, $url)
|
||||||
{
|
{
|
||||||
$hcard = self::_hcard($body, $url);
|
$hcard = self::_hcard($body, $url);
|
||||||
|
|
||||||
@ -119,7 +122,7 @@ class DiscoveryHints {
|
|||||||
return $hints;
|
return $hints;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function _hcard($body, $url)
|
public static function _hcard($body, $url)
|
||||||
{
|
{
|
||||||
$mf2 = new Mf2\Parser($body, $url);
|
$mf2 = new Mf2\Parser($body, $url);
|
||||||
$mf2 = $mf2->parse();
|
$mf2 = $mf2->parse();
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,205 +42,215 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class Activitypub_explorer
|
class Activitypub_explorer
|
||||||
{
|
{
|
||||||
private $discovered_actor_profiles = array ();
|
private $discovered_actor_profiles = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get every profile from the given URL
|
* Get every profile from the given URL
|
||||||
* This function cleans the $this->discovered_actor_profiles array
|
* This function cleans the $this->discovered_actor_profiles array
|
||||||
* so that there is no erroneous data
|
* so that there is no erroneous data
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param string $url User's url
|
* @param string $url User's url
|
||||||
* @return array of Profile objects
|
* @return array of Profile objects
|
||||||
*/
|
*/
|
||||||
public function lookup ($url)
|
public function lookup($url)
|
||||||
{
|
{
|
||||||
$this->discovered_actor_profiles = array ();
|
$this->discovered_actor_profiles = array();
|
||||||
|
|
||||||
return $this->_lookup ($url);
|
return $this->_lookup($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get every profile from the given URL
|
||||||
|
* This is a recursive function that will accumulate the results on
|
||||||
|
* $discovered_actor_profiles array
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param string $url User's url
|
||||||
|
* @return array of Profile objects
|
||||||
|
*/
|
||||||
|
private function _lookup($url)
|
||||||
|
{
|
||||||
|
// First check if we already have it locally and, if so, return it
|
||||||
|
// If the local fetch fails: grab it remotely, store locally and return
|
||||||
|
if (! ($this->grab_local_user($url) || $this->grab_remote_user($url))) {
|
||||||
|
throw new Exception("User not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return $this->discovered_actor_profiles;
|
||||||
* Get every profile from the given URL
|
}
|
||||||
* This is a recursive function that will accumulate the results on
|
|
||||||
* $discovered_actor_profiles array
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param string $url User's url
|
|
||||||
* @return array of Profile objects
|
|
||||||
*/
|
|
||||||
private function _lookup ($url)
|
|
||||||
{
|
|
||||||
// First check if we already have it locally and, if so, return it
|
|
||||||
// If the local fetch fails: grab it remotely, store locally and return
|
|
||||||
if (! ($this->grab_local_user ($url) || $this->grab_remote_user ($url))) {
|
|
||||||
throw new Exception ("User not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
return $this->discovered_actor_profiles;
|
* This ensures that we are using a valid ActivityPub URI
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param string $url
|
||||||
|
* @return boolean success state (related to the response)
|
||||||
|
* @throws Exception (If the HTTP request fails)
|
||||||
|
*/
|
||||||
|
private function ensure_proper_remote_uri($url)
|
||||||
|
{
|
||||||
|
$client = new HTTPClient();
|
||||||
|
$headers = array();
|
||||||
|
$headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
||||||
|
$headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
|
||||||
|
$response = $client->get($url, $headers);
|
||||||
|
if (!$response->isOk()) {
|
||||||
|
throw new Exception("Invalid Actor URL.");
|
||||||
|
}
|
||||||
|
$res = json_decode($response->getBody(), JSON_UNESCAPED_SLASHES);
|
||||||
|
if (self::validate_remote_response($res)) {
|
||||||
|
$this->temp_res = $res;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return false;
|
||||||
* Get a local user profiles from its URL and joins it on
|
}
|
||||||
* $this->discovered_actor_profiles
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param string $url User's url
|
|
||||||
* @return boolean success state
|
|
||||||
*/
|
|
||||||
private function grab_local_user ($url)
|
|
||||||
{
|
|
||||||
if (($actor_profile = self::get_profile_by_url ($url)) != false) {
|
|
||||||
$this->discovered_actor_profiles[]= $actor_profile;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
/******************************** XXX: ********************************
|
|
||||||
* Sometimes it is not true that the user is not locally available, *
|
|
||||||
* mostly when it is a local user and URLs slightly changed *
|
|
||||||
* e.g.: GS instance owner changed from standard urls to pretty urls *
|
|
||||||
* (not sure if this is necessary, but anyway) *
|
|
||||||
**********************************************************************/
|
|
||||||
|
|
||||||
// Iff we really are in the same instance
|
/**
|
||||||
$root_url_len = strlen (common_root_url ());
|
* Get a local user profiles from its URL and joins it on
|
||||||
if (substr ($url, 0, $root_url_len) == common_root_url ()) {
|
* $this->discovered_actor_profiles
|
||||||
// Grab the nickname and try to get the user
|
*
|
||||||
if (($actor_profile = Profile::getKV ("nickname", substr ($url, $root_url_len))) != false) {
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
$this->discovered_actor_profiles[]= $actor_profile;
|
* @param string $uri Actor's uri
|
||||||
return true;
|
* @return boolean success state
|
||||||
}
|
*/
|
||||||
}
|
private function grab_local_user($uri)
|
||||||
}
|
{
|
||||||
return false;
|
// Ensure proper remote URI
|
||||||
|
// If an exceptiong ocurrs here it's better to just leave everything
|
||||||
|
// break than to continue processing
|
||||||
|
if ($this->ensure_proper_remote_uri($uri)) {
|
||||||
|
$uri = $this->temp_res["id"];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Try standard ActivityPub route
|
||||||
|
$aprofile = Activitypub_profile::getKV("uri", $uri);
|
||||||
|
if ($aprofile instanceof Activitypub_profile) {
|
||||||
|
$profile = $aprofile->local_profile();
|
||||||
|
} else {
|
||||||
|
// This potential local user is not a remote user.
|
||||||
|
// Let's check for pure blood!
|
||||||
|
$profile = User::getByNickname($this->temp_res["preferredUsername"])->getProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found something!
|
||||||
|
$this->discovered_actor_profiles[]= $profile;
|
||||||
|
unset($this->temp_res); // IMPORTANT to avoid _dangerous_ noise in the Explorer system
|
||||||
|
return true;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// We can safely ignore every exception here as we are return false
|
||||||
|
// when it fails the lookup for existing local representation
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return false;
|
||||||
* Get a remote user(s) profile(s) from its URL and joins it on
|
}
|
||||||
* $this->discovered_actor_profiles
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param string $url User's url
|
|
||||||
* @return boolean success state
|
|
||||||
*/
|
|
||||||
private function grab_remote_user ($url)
|
|
||||||
{
|
|
||||||
$client = new HTTPClient ();
|
|
||||||
$headers = array();
|
|
||||||
$headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
|
||||||
$headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
|
|
||||||
$response = $client->get ($url, $headers);
|
|
||||||
if (!$response->isOk ()) {
|
|
||||||
throw new Exception ("Invalid Actor URL.");
|
|
||||||
}
|
|
||||||
$res = json_decode ($response->getBody (), JSON_UNESCAPED_SLASHES);
|
|
||||||
if (isset ($res["orderedItems"])) { // It's a potential collection of actors!!!
|
|
||||||
foreach ($res["orderedItems"] as $profile) {
|
|
||||||
if ($this->_lookup ($profile) == false) {
|
|
||||||
// XXX: Invalid actor found, not sure how we handle those
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Go through entire collection
|
|
||||||
if (!is_null ($res["next"])) {
|
|
||||||
$this->_lookup ($res["next"]);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else if (self::validate_remote_response ($res)) {
|
|
||||||
$this->discovered_actor_profiles[]= $this->store_profile ($res);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Get a remote user(s) profile(s) from its URL and joins it on
|
||||||
|
* $this->discovered_actor_profiles
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param string $url User's url
|
||||||
|
* @return boolean success state
|
||||||
|
*/
|
||||||
|
private function grab_remote_user($url)
|
||||||
|
{
|
||||||
|
if (!isset($this->temp_res)) {
|
||||||
|
$client = new HTTPClient();
|
||||||
|
$headers = array();
|
||||||
|
$headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
||||||
|
$headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
|
||||||
|
$response = $client->get($url, $headers);
|
||||||
|
if (!$response->isOk()) {
|
||||||
|
throw new Exception("Invalid Actor URL.");
|
||||||
|
}
|
||||||
|
$res = json_decode($response->getBody(), JSON_UNESCAPED_SLASHES);
|
||||||
|
} else {
|
||||||
|
$res = $this->temp_res;
|
||||||
|
unset($this->temp_res);
|
||||||
|
}
|
||||||
|
if (isset($res["orderedItems"])) { // It's a potential collection of actors!!!
|
||||||
|
foreach ($res["orderedItems"] as $profile) {
|
||||||
|
if ($this->_lookup($profile) == false) {
|
||||||
|
// XXX: Invalid actor found, not sure how we handle those
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Go through entire collection
|
||||||
|
if (!is_null($res["next"])) {
|
||||||
|
$this->_lookup($res["next"]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} elseif (self::validate_remote_response($res)) {
|
||||||
|
$this->discovered_actor_profiles[]= $this->store_profile($res);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return false;
|
||||||
* Save remote user profile in local instance
|
}
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param array $res remote response
|
|
||||||
* @return Profile remote Profile object
|
|
||||||
*/
|
|
||||||
private function store_profile ($res)
|
|
||||||
{
|
|
||||||
$aprofile = new Activitypub_profile;
|
|
||||||
$aprofile->uri = $res["url"];
|
|
||||||
$aprofile->nickname = $res["nickname"];
|
|
||||||
$aprofile->fullname = $res["display_name"];
|
|
||||||
$aprofile->bio = substr ($res["summary"], 0, 1000);
|
|
||||||
$aprofile->inboxuri = $res["inbox"];
|
|
||||||
$aprofile->sharedInboxuri = isset ($res["sharedInbox"]) ? $res["sharedInbox"] : $res["inbox"];
|
|
||||||
|
|
||||||
$aprofile->do_insert ();
|
/**
|
||||||
|
* Save remote user profile in local instance
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param array $res remote response
|
||||||
|
* @return Profile remote Profile object
|
||||||
|
*/
|
||||||
|
private function store_profile($res)
|
||||||
|
{
|
||||||
|
$aprofile = new Activitypub_profile;
|
||||||
|
$aprofile->uri = $res["id"];
|
||||||
|
$aprofile->nickname = $res["preferredUsername"];
|
||||||
|
$aprofile->fullname = $res["name"];
|
||||||
|
$aprofile->bio = substr($res["summary"], 0, 1000);
|
||||||
|
$aprofile->inboxuri = $res["inbox"];
|
||||||
|
$aprofile->sharedInboxuri = isset($res["sharedInbox"]) ? $res["sharedInbox"] : $res["inbox"];
|
||||||
|
|
||||||
return $aprofile->local_profile ();
|
$aprofile->do_insert();
|
||||||
|
|
||||||
|
return $aprofile->local_profile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a remote response in order to determine whether this
|
||||||
|
* response is a valid profile or not
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param array $res remote response
|
||||||
|
* @return boolean success state
|
||||||
|
*/
|
||||||
|
private static function validate_remote_response($res)
|
||||||
|
{
|
||||||
|
if (!isset($res["id"], $res["preferredUsername"], $res["name"], $res["summary"], $res["inbox"])) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return true;
|
||||||
* Validates a remote response in order to determine whether this
|
}
|
||||||
* response is a valid profile or not
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param array $res remote response
|
|
||||||
* @return boolean success state
|
|
||||||
*/
|
|
||||||
private static function validate_remote_response ($res)
|
|
||||||
{
|
|
||||||
if (!isset ($res["url"], $res["nickname"], $res["display_name"], $res["summary"], $res["inbox"])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
/**
|
||||||
|
* Given a valid actor profile url returns its inboxes
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param string $url of Actor profile
|
||||||
|
* @return boolean|array false if fails | array with inbox and shared inbox if successful
|
||||||
|
*/
|
||||||
|
public static function get_actor_inboxes_uri($url)
|
||||||
|
{
|
||||||
|
$client = new HTTPClient();
|
||||||
|
$headers = array();
|
||||||
|
$headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
||||||
|
$headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
|
||||||
|
$response = $client->get($url, $headers);
|
||||||
|
if (!$response->isOk()) {
|
||||||
|
throw new Exception("Invalid Actor URL.");
|
||||||
|
}
|
||||||
|
$res = json_decode($response->getBody(), JSON_UNESCAPED_SLASHES);
|
||||||
|
if (self::validate_remote_response($res)) {
|
||||||
|
return array("inbox" => $res["inbox"],
|
||||||
|
"sharedInbox" => isset($res["sharedInbox"]) ? $res["sharedInbox"] : $res["inbox"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return false;
|
||||||
* Get a profile from it's profileurl
|
}
|
||||||
* Unfortunately GNU Social cache is not truly reliable when handling
|
|
||||||
* potential ActivityPub remote profiles, as so it is important to use
|
|
||||||
* this hacky workaround (at least for now)
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param string $v URL
|
|
||||||
* @return boolean|Profile false if fails | Profile object if successful
|
|
||||||
*/
|
|
||||||
public static function get_profile_by_url ($v)
|
|
||||||
{
|
|
||||||
$i = Managed_DataObject::getcached("Profile", "profileurl", $v);
|
|
||||||
if (empty ($i)) { // false = cache miss
|
|
||||||
$i = new Profile;
|
|
||||||
$result = $i->get ("profileurl", $v);
|
|
||||||
if ($result) {
|
|
||||||
// Hit!
|
|
||||||
$i->encache();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a valid actor profile url returns its inboxes
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param string $url of Actor profile
|
|
||||||
* @return boolean|array false if fails | array with inbox and shared inbox if successful
|
|
||||||
*/
|
|
||||||
public static function get_actor_inboxes_uri ($url)
|
|
||||||
{
|
|
||||||
$client = new HTTPClient ();
|
|
||||||
$headers = array();
|
|
||||||
$headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
|
||||||
$headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
|
|
||||||
$response = $client->get ($url, $headers);
|
|
||||||
if (!$response->isOk ()) {
|
|
||||||
throw new Exception ("Invalid Actor URL.");
|
|
||||||
}
|
|
||||||
$res = json_decode ($response->getBody (), JSON_UNESCAPED_SLASHES);
|
|
||||||
if (self::validate_remote_response ($res)) {
|
|
||||||
return array ("inbox" => $res["inbox"],
|
|
||||||
"sharedInbox" => isset ($res["sharedInbox"]) ? $res["sharedInbox"] : $res["inbox"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
* @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/
|
||||||
*/
|
*/
|
||||||
if (!defined ('GNUSOCIAL')) {
|
if (!defined('GNUSOCIAL')) {
|
||||||
exit (1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,184 +43,202 @@ if (!defined ('GNUSOCIAL')) {
|
|||||||
*/
|
*/
|
||||||
class Activitypub_postman
|
class Activitypub_postman
|
||||||
{
|
{
|
||||||
private $actor;
|
private $actor;
|
||||||
private $to = array ();
|
private $to = [];
|
||||||
private $client;
|
private $client;
|
||||||
private $headers;
|
private $headers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a postman to deliver something to someone
|
* Create a postman to deliver something to someone
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Profile of sender
|
* @param Profile of sender
|
||||||
* @param Activitypub_profile $to array of destinataries
|
* @param Activitypub_profile $to array of destinataries
|
||||||
*/
|
*/
|
||||||
public function __construct ($from, $to = array ())
|
public function __construct($from, $to = [])
|
||||||
{
|
{
|
||||||
$this->client = new HTTPClient ();
|
$this->client = new HTTPClient();
|
||||||
$this->actor = $from;
|
$this->actor = $from;
|
||||||
$this->to = $to;
|
$this->to = $to;
|
||||||
$this->headers = array();
|
$this->headers = [];
|
||||||
$this->headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
$this->headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
||||||
$this->headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
|
$this->headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a follow notification to remote instance
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function follow()
|
||||||
|
{
|
||||||
|
$data = Activitypub_follow::follow_to_array($this->actor->getUrl(), $this->to[0]->getUrl());
|
||||||
|
$this->client->setBody(json_encode($data));
|
||||||
|
$res = $this->client->post($this->to[0]->get_inbox(), $this->headers);
|
||||||
|
$res_body = json_decode($res->getBody());
|
||||||
|
|
||||||
|
if ($res->isOk() || $res->getStatus() == 409) {
|
||||||
|
$pending_list = new Activitypub_pending_follow_requests($this->actor->getID(), $this->to[0]->getID());
|
||||||
|
if (! ($res->getStatus() == 409 || $res_body->type == "Accept")) {
|
||||||
|
$pending_list->add();
|
||||||
|
throw new Exception("Your follow request is pending acceptation.");
|
||||||
|
}
|
||||||
|
$pending_list->remove();
|
||||||
|
return true;
|
||||||
|
} elseif (isset($res_body[0]->error)) {
|
||||||
|
throw new Exception($res_body[0]->error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
throw new Exception("An unknown error occurred.");
|
||||||
* Send a follow notification to remote instance
|
}
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
*/
|
|
||||||
public function follow ()
|
|
||||||
{
|
|
||||||
$data = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
|
||||||
"type" => "Follow",
|
|
||||||
"actor" => $this->actor->getUrl (),
|
|
||||||
"object" => $this->to[0]->getUrl ());
|
|
||||||
$this->client->setBody (json_encode ($data));
|
|
||||||
$this->client->post ($this->to[0]->get_inbox (), $this->headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a Undo Follow notification to remote instance
|
* Send a Undo Follow notification to remote instance
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
*/
|
*/
|
||||||
public function undo_follow ()
|
public function undo_follow()
|
||||||
{
|
{
|
||||||
$data = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
$data = Activitypub_undo::undo_to_array(
|
||||||
"type" => "Undo",
|
Activitypub_follow::follow_to_array(
|
||||||
"actor" => $this->actor->getUrl (),
|
$this->actor->getUrl(),
|
||||||
"object" => array (
|
$this->to[0]->getUrl()
|
||||||
"type" => "Follow",
|
)
|
||||||
"object" => $this->to[0]->getUrl ()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
$this->client->setBody (json_encode ($data));
|
$this->client->setBody(json_encode($data));
|
||||||
$this->client->post ($this->to[0]->get_inbox (), $this->headers);
|
$res = $this->client->post($this->to[0]->get_inbox(), $this->headers);
|
||||||
}
|
$res_body = json_decode($res->getBody());
|
||||||
|
|
||||||
/**
|
if ($res->isOk() || $res->getStatus() == 409) {
|
||||||
* Send a Like notification to remote instances holding the notice
|
$pending_list = new Activitypub_pending_follow_requests($this->actor->getID(), $this->to[0]->getID());
|
||||||
*
|
$pending_list->remove();
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
return true;
|
||||||
* @param Notice $notice
|
|
||||||
*/
|
|
||||||
public function like ($notice)
|
|
||||||
{
|
|
||||||
$data = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
|
||||||
"type" => "Like",
|
|
||||||
"actor" => $this->actor->getUrl (),
|
|
||||||
"object" => $notice->getUri ());
|
|
||||||
$this->client->setBody (json_encode ($data));
|
|
||||||
foreach ($this->to_inbox () as $inbox) {
|
|
||||||
$this->client->post ($inbox, $this->headers);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (isset($res_body[0]->error)) {
|
||||||
|
throw new Exception($res_body[0]->error);
|
||||||
|
}
|
||||||
|
throw new Exception("An unknown error occurred.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a Undo Like notification to remote instances holding the notice
|
* Send a Like notification to remote instances holding the notice
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Notice $notice
|
* @param Notice $notice
|
||||||
*/
|
*/
|
||||||
public function undo_like ($notice)
|
public function like($notice)
|
||||||
{
|
{
|
||||||
$data = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
$data = Activitypub_like::like_to_array(
|
||||||
"type" => "Undo",
|
$this->actor->getUrl(),
|
||||||
"actor" => $this->actor->getUrl (),
|
Activitypub_notice::notice_to_array($notice)
|
||||||
"object" => array (
|
|
||||||
"type" => "Like",
|
|
||||||
"object" => $notice->getUri ()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
$this->client->setBody (json_encode ($data));
|
$this->client->setBody(json_encode($data));
|
||||||
foreach ($this->to_inbox () as $inbox) {
|
foreach ($this->to_inbox() as $inbox) {
|
||||||
$this->client->post ($inbox, $this->headers);
|
$this->client->post($inbox, $this->headers);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a Announce notification to remote instances
|
* Send a Undo Like notification to remote instances holding the notice
|
||||||
*
|
*
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
* @param Notice $notice
|
* @param Notice $notice
|
||||||
*/
|
*/
|
||||||
public function announce ($notice)
|
public function undo_like($notice)
|
||||||
{
|
{
|
||||||
$data = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
$data = Activitypub_undo::undo_to_array(
|
||||||
"id" => $notice->getUri (),
|
Activitypub_like::like_to_array(
|
||||||
"url" => $notice->getUrl (),
|
$this->actor->getUrl(),
|
||||||
"type" => "Announce",
|
Activitypub_notice::notice_to_array($notice)
|
||||||
"actor" => $this->actor->getUrl (),
|
)
|
||||||
"to" => "https://www.w3.org/ns/activitystreams#Public",
|
|
||||||
"object" => $notice->getUri ()
|
|
||||||
);
|
|
||||||
$this->client->setBody (json_encode ($data));
|
|
||||||
foreach ($this->to_inbox () as $inbox) {
|
|
||||||
$this->client->post ($inbox, $this->headers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a Create notification to remote instances
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param Notice $notice
|
|
||||||
*/
|
|
||||||
public function create ($notice)
|
|
||||||
{
|
|
||||||
$data = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
|
||||||
"id" => $notice->getUri (),
|
|
||||||
"type" => "Create",
|
|
||||||
"actor" => $this->actor->getUrl (),
|
|
||||||
"to" => "https://www.w3.org/ns/activitystreams#Public",
|
|
||||||
"object" => array (
|
|
||||||
"type" => "Note",
|
|
||||||
"url" => $notice->getUrl (),
|
|
||||||
"content" => $notice->getContent ()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
if (isset ($notice->reply_to)) {
|
|
||||||
$data["object"]["reply_to"] = $notice->getParent ()->getUri ();
|
|
||||||
}
|
|
||||||
$this->client->setBody (json_encode ($data));
|
|
||||||
foreach ($this->to_inbox () as $inbox) {
|
|
||||||
$this->client->post ($inbox, $this->headers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a Delete notification to remote instances holding the notice
|
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @param Notice $notice
|
|
||||||
*/
|
|
||||||
public function delete ($notice)
|
|
||||||
{
|
|
||||||
$data = array ("@context" => "https://www.w3.org/ns/activitystreams",
|
|
||||||
"type" => "Delete",
|
|
||||||
"actor" => $this->actor->getUrl (),
|
|
||||||
"object" => $notice->getUri ()
|
|
||||||
);
|
);
|
||||||
$this->client->setBody (json_encode ($data));
|
$this->client->setBody(json_encode($data));
|
||||||
foreach ($this->to_inbox () as $inbox) {
|
foreach ($this->to_inbox() as $inbox) {
|
||||||
$this->client->post ($inbox, $this->headers);
|
$this->client->post($inbox, $this->headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a Create notification to remote instances
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Notice $notice
|
||||||
|
*/
|
||||||
|
public function create($notice)
|
||||||
|
{
|
||||||
|
$data = Activitypub_create::create_to_array(
|
||||||
|
$notice->getUri(),
|
||||||
|
$this->actor->getUrl(),
|
||||||
|
Activitypub_notice::notice_to_array($notice)
|
||||||
|
);
|
||||||
|
if (isset($notice->reply_to)) {
|
||||||
|
$data["object"]["reply_to"] = $notice->getParent()->getUri();
|
||||||
|
}
|
||||||
|
$this->client->setBody(json_encode($data));
|
||||||
|
foreach ($this->to_inbox() as $inbox) {
|
||||||
|
$this->client->post($inbox, $this->headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a Announce notification to remote instances
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Notice $notice
|
||||||
|
*/
|
||||||
|
public function announce($notice)
|
||||||
|
{
|
||||||
|
$data = Activitypub_announce::announce_to_array(
|
||||||
|
$this->actor->getUrl(),
|
||||||
|
Activitypub_notice::notice_to_array($notice)
|
||||||
|
);
|
||||||
|
$this->client->setBody(json_encode($data));
|
||||||
|
foreach ($this->to_inbox() as $inbox) {
|
||||||
|
$this->client->post($inbox, $this->headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a Delete notification to remote instances holding the notice
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @param Notice $notice
|
||||||
|
*/
|
||||||
|
public function delete($notice)
|
||||||
|
{
|
||||||
|
$data = Activitypub_delete::delete_to_array(Activitypub_notice::notice_to_array($notice));
|
||||||
|
$this->client->setBody(json_encode($data));
|
||||||
|
$errors = array();
|
||||||
|
foreach ($this->to_inbox() as $inbox) {
|
||||||
|
$res = $this->client->post($inbox, $this->headers);
|
||||||
|
if (!$res->isOk()) {
|
||||||
|
$res_body = json_decode($res->getBody());
|
||||||
|
if (isset($res_body[0]->error)) {
|
||||||
|
$errors[] = ($res_body[0]->error);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
$errors[] = ("An unknown error occurred.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($errors)) {
|
||||||
|
throw new Exception(json_encode($errors));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean list of inboxes to deliver messages
|
||||||
|
*
|
||||||
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
* @return array To Inbox URLs
|
||||||
|
*/
|
||||||
|
private function to_inbox()
|
||||||
|
{
|
||||||
|
$to_inboxes = array();
|
||||||
|
foreach ($this->to as $to_profile) {
|
||||||
|
$to_inboxes[] = $to_profile->get_inbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return array_unique($to_inboxes);
|
||||||
* Clean list of inboxes to deliver messages
|
}
|
||||||
*
|
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
|
||||||
* @return array To Inbox URLs
|
|
||||||
*/
|
|
||||||
private function to_inbox ()
|
|
||||||
{
|
|
||||||
$to_inboxes = array ();
|
|
||||||
foreach ($this->to as $to_profile) {
|
|
||||||
$to_inboxes[] = $to_profile->get_inbox ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_unique ($to_inboxes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user