Fixed various bugs, improved and refactored some stuff

(remote avatars are working)
This commit is contained in:
Diogo Cordeiro 2018-08-02 18:02:28 +01:00
parent cfc4eece38
commit aa491271f7
15 changed files with 109 additions and 116 deletions

View File

@ -39,7 +39,7 @@ require_once __DIR__ . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR . "ex
require_once __DIR__ . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR . "postman.php";
// So that this isn't hardcoded everywhere
define('ACTIVITYPUB_BASE_INSTANCE_URI', common_root_url().'index.php/user/');
define('ACTIVITYPUB_BASE_ACTOR_URI', common_root_url().'index.php/user/');
const ACTIVITYPUB_PUBLIC_TO = ['https://www.w3.org/ns/activitystreams#Public',
'Public',
'as:Public'
@ -65,7 +65,7 @@ class ActivityPubPlugin extends Plugin
public static function actor_uri($profile)
{
if ($profile->isLocal()) {
return ACTIVITYPUB_BASE_INSTANCE_URI.$profile->getID();
return ACTIVITYPUB_BASE_ACTOR_URI.$profile->getID();
} else {
return $profile->getUri();
}
@ -254,7 +254,7 @@ class ActivityPubPlugin extends Plugin
$out->elementStart('dl', 'entity_tags activitypub_profile');
$out->element('dt', null, _m('ActivityPub'));
$out->element('dd', null, _m('Active'));
$out->element('dd', null, _m('Remote Profile'));
$out->elementEnd('dl');
}
@ -513,7 +513,7 @@ class ActivityPubPlugin extends Plugin
* @param string $uri in/out
* @return mixed hook return code
*/
public function onStartGetProfileUri($profile, &$uri)
public function onStartGetProfileUri(Profile $profile, &$uri)
{
$aprofile = Activitypub_profile::getKV('profile_id', $profile->id);
if ($aprofile instanceof Activitypub_profile) {
@ -952,12 +952,18 @@ class ActivityPubReturn
* @param array $mimeTypes Supported Types
* @return array|null of supported mime types sorted | null if none valid
*/
public static function getBestSupportedMimeType($mimeTypes = null)
public static function getBestSupportedMimeType($mimeTypes)
{
// XXX: This function needs improvement!
if (!isset($_SERVER['HTTP_ACCEPT'])) {
return null;
}
// This mime type was messing everything, thus the special case
if ($_SERVER['HTTP_ACCEPT'] == 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"') {
return true;
}
// Values will be stored in this array
$AcceptTypes = [];
@ -970,7 +976,7 @@ class ActivityPubReturn
$q = 1;
// check if there is a different quality
if (strpos($a, ';q=')) {
// divide "mime/type;q=X" into two parts: "mime/type" i "X"
// divide "mime/type;q=X" into two parts: "mime/type" and "X"
list($a, $q) = explode(';q=', $a);
}
// mime-type $a is accepted with the quality $q
@ -979,12 +985,7 @@ class ActivityPubReturn
}
arsort($AcceptTypes);
// if no parameter was passed, just return parsed data
if (!$mimeTypes) {
return $AcceptTypes;
}
$mimeTypes = array_map('strtolower', (array)$mimeTypes);
$mimeTypes = array_map('strtolower', $mimeTypes);
// lets check our supported types:
foreach ($AcceptTypes as $mime => $q) {
@ -992,6 +993,7 @@ class ActivityPubReturn
return $mime;
}
}
// no mime-type found
return null;
}

View File

@ -68,62 +68,56 @@ class apActorInboxAction extends ManagedAction
common_debug('ActivityPub Inbox: Received a POST request.');
$data = file_get_contents('php://input');
common_debug('ActivityPub Inbox: Request contents: '.$data);
$data = json_decode(file_get_contents('php://input'));
$data = json_decode(file_get_contents('php://input'), true);
// Validate data
if (!(isset($data->type))) {
if (!(isset($data['type']))) {
ActivityPubReturn::error('Type was not specified.');
}
if (!isset($data->actor)) {
if (!isset($data['actor'])) {
ActivityPubReturn::error('Actor was not specified.');
}
if (!isset($data->object)) {
if (!isset($data['object'])) {
ActivityPubReturn::error('Object was not specified.');
}
// Get valid Actor object
try {
$actor_profile = ActivityPub_explorer::get_profile_from_url($data->actor);
$actor_profile = ActivityPub_explorer::get_profile_from_url($data['actor']);
} catch (Exception $e) {
ActivityPubReturn::error($e->getMessage(), 404);
}
// Public To:
$public_to = ['https://www.w3.org/ns/activitystreams#Public',
'Public',
'as:Public'
];
$to_profiles = [$profile];
// Process request
switch ($data->type) {
case "Create":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Create.php";
break;
case "Delete":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Delete.php";
break;
case "Follow":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Follow.php";
break;
case "Like":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Like.php";
break;
case "Undo":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Undo.php";
break;
case "Announce":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Announce.php";
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:
ActivityPubReturn::error("Invalid type value.");
}
switch ($data['type']) {
case "Create":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Create.php";
break;
case "Delete":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Delete.php";
break;
case "Follow":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Follow.php";
break;
case "Like":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Like.php";
break;
case "Undo":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Undo.php";
break;
case "Announce":
require_once __DIR__ . DIRECTORY_SEPARATOR . "inbox" . DIRECTORY_SEPARATOR . "Announce.php";
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:
ActivityPubReturn::error("Invalid type value.");
}
}
}

0
actions/apnotice.php Normal file → Executable file
View File

View File

@ -58,36 +58,30 @@ class apSharedInboxAction extends ManagedAction
common_debug('ActivityPub Shared Inbox: Received a POST request.');
$data = file_get_contents('php://input');
common_debug('ActivityPub Shared Inbox: Request contents: '.$data);
$data = json_decode(file_get_contents('php://input'));
$data = json_decode(file_get_contents('php://input'), true);
// Validate data
if (!isset($data->type)) {
if (!isset($data['type'])) {
ActivityPubReturn::error('Type was not specified.');
}
if (!isset($data->actor)) {
if (!isset($data['actor'])) {
ActivityPubReturn::error('Actor was not specified.');
}
if (!isset($data->object)) {
if (!isset($data['object'])) {
ActivityPubReturn::error('Object was not specified.');
}
// Get valid Actor object
try {
$actor_profile = ActivityPub_explorer::get_profile_from_url($data->actor);
$actor_profile = ActivityPub_explorer::get_profile_from_url($data['actor']);
} catch (Exception $e) {
ActivityPubReturn::error($e->getMessage(), 404);
}
// Public To:
$public_to = ['https://www.w3.org/ns/activitystreams#Public',
'Public',
'as:Public'
];
$to_profiles = ['https://www.w3.org/ns/activitystreams#Public'];
$to_profiles = [];
// Process request
switch ($data->type) {
switch ($data['type']) {
// Data available:
// Profile $actor_profile
// string|object $data->object

View File

@ -30,20 +30,20 @@ if (!defined('GNUSOCIAL')) {
}
// Validate data
if (!isset($data->type)) {
if (!isset($data['object']['type'])) {
ActivityPubReturn::error("Type was not specified.");
}
switch ($data->object->type) {
case "Follow":
switch ($data['object']['type']) {
case "Follow":
// Validate data
if (!isset($data->object->object)) {
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];
$object_profile = $object_profile->lookup($data['object']['object'])[0];
} catch (Exception $e) {
ActivityPubReturn::error("Invalid Object Actor URL.", 404);
}
@ -52,7 +52,7 @@ case "Follow":
$pending_list->remove();
ActivityPubReturn::answer(); // You are now being followed by this person.
break;
default:
default:
ActivityPubReturn::error("Invalid object type.");
break;
}

View File

@ -31,7 +31,7 @@ if (!defined('GNUSOCIAL')) {
try {
try {
$object_notice = ActivityPubPlugin::grab_notice_from_url($data->object);
$object_notice = ActivityPubPlugin::grab_notice_from_url($data['object']);
} catch (Exception $e) {
ActivityPubReturn::error('Invalid Object specified.');
}

View File

@ -31,10 +31,10 @@ if (!defined('GNUSOCIAL')) {
$valid_object_types = ['Note'];
$res = $data->object;
$res = $data['object'];
try {
Activitypub_notice::validate_remote_notice((array) $res);
Activitypub_notice::validate_remote_notice($res);
} catch (Exception $e) {
common_debug('ActivityPub Inbox Create Note: Invalid note: '.$e->getMessage());
ActivityPubReturn::error($e->getMessage());
@ -42,23 +42,23 @@ try {
$settings = [];
if (isset($res->inReplyTo)) {
$settings['inReplyTo'] = $res->inReplyTo;
if (isset($res['inReplyTo'])) {
$settings['inReplyTo'] = $res['inReplyTo'];
}
if (isset($res->latitude)) {
$settings['latitude'] = $res->latitude;
if (isset($res['latitude'])) {
$settings['latitude'] = $res['latitude'];
}
if (isset($res->longitude)) {
$settings['longitude'] = $res->longitude;
if (isset($res['longitude'])) {
$settings['longitude'] = $res['longitude'];
}
try {
Activitypub_notice::create_notice(
$actor_profile,
$res->id,
$res->url,
$res->content,
$res->cc,
$res['id'],
$res['url'],
$res['content'],
$res['cc'],
$settings
);
ActivityPubReturn::answer();

View File

@ -30,7 +30,7 @@ if (!defined('GNUSOCIAL')) {
}
try {
$notice = ActivityPubPlugin::grab_notice_from_url($data->object->id);
$notice = ActivityPubPlugin::grab_notice_from_url($data['object']['id']);
$notice->deleteAs($actor_profile);
ActivityPubReturn::answer();
} catch (Exception $e) {

View File

@ -30,7 +30,7 @@ if (!defined('GNUSOCIAL')) {
}
// Validate Object
if (!filter_var($data->object, FILTER_VALIDATE_URL)) {
if (!filter_var($data['object'], FILTER_VALIDATE_URL)) {
ActivityPubReturn::error('Invalid Object Actor URL.');
}
@ -38,7 +38,7 @@ if (!filter_var($data->object, FILTER_VALIDATE_URL)) {
try {
if (!isset($profile)) {
$object_profile = new Activitypub_explorer;
$object_profile = $object_profile->lookup($data->object)[0];
$object_profile = $object_profile->lookup($data['object'])[0];
} else {
$object_profile = $profile;
unset($profile);
@ -52,14 +52,14 @@ $actor_aprofile = Activitypub_profile::from_profile($actor_profile);
if (!Subscription::exists($actor_profile, $object_profile)) {
Subscription::start($actor_profile, $object_profile);
common_debug('ActivityPubPlugin: Accepted Follow request from '.$data->actor.' to '.$data->object);
common_debug('ActivityPubPlugin: Accepted Follow request from '.$data['actor'].' to '.$data['object']);
// Notify remote instance that we have accepted their request
common_debug('ActivityPubPlugin: Notifying remote instance that we have accepted their Follow request request from '.$data->actor.' to '.$data->object);
common_debug('ActivityPubPlugin: Notifying remote instance that we have accepted their Follow request request from '.$data['actor'].' to '.$data['object']);
$postman = new Activitypub_postman($actor_profile, [$actor_aprofile]);
$postman->follow();
ActivityPubReturn::answer();
} else {
common_debug('ActivityPubPlugin: Received a repeated Follow request from '.$data->actor.' to '.$data->object);
common_debug('ActivityPubPlugin: Received a repeated Follow request from '.$data['actor'].' to '.$data['object']);
ActivityPubReturn::error('Already following.', 409);
}

View File

@ -31,7 +31,7 @@ if (!defined('GNUSOCIAL')) {
try {
try {
$object_notice = ActivityPubPlugin::grab_notice_from_url($data->object);
$object_notice = ActivityPubPlugin::grab_notice_from_url($data['object']);
} catch (Exception $e) {
ActivityPubReturn::error('Invalid Object specified.');
}

View File

@ -30,18 +30,18 @@ if (!defined('GNUSOCIAL')) {
}
// Validate data
if (!isset($data->type)) {
if (!isset($data['type'])) {
ActivityPubReturn::error('Type was not specified.');
}
switch ($data->object->type) {
switch ($data['object']['type']) {
case 'Like':
try {
// Validate data
if (!isset($data->object->object)) {
if (!isset($data['object']['object'])) {
ActivityPubReturn::error('Notice URI was not specified.');
}
Fave::removeEntry($actor_profile, ActivityPubPlugin::grab_notice_from_url($data->object->object));
Fave::removeEntry($actor_profile, ActivityPubPlugin::grab_notice_from_url($data['object']['object']));
// Notice disfavorited successfully.
ActivityPubReturn::answer();
} catch (Exception $e) {
@ -50,13 +50,13 @@ switch ($data->object->type) {
break;
case 'Follow':
// Validate data
if (!isset($data->object->object)) {
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];
$object_profile = $object_profile->lookup($data['object']['object'])[0];
} catch (Exception $e) {
ActivityPubReturn::error('Invalid Object Actor URL.', 404);
}

0
classes/Activitypub_mention_tag.php Normal file → Executable file
View File

View File

@ -318,11 +318,9 @@ class Activitypub_profile extends Managed_DataObject
*/
public static function fromUri($url)
{
$explorer = new Activitypub_explorer();
$profiles_found = $explorer->lookup($url);
if (!empty($profiles_found)) {
return self::from_profile($profiles_found[0]);
} else {
try {
return self::from_profile(Activitypub_explorer::get_profile_from_url($url));
} catch (Exception $e) {
throw new Exception('No valid ActivityPub profile found for given URI.');
}
}

0
tests/Unit/HTTPSignatureTest.php Normal file → Executable file
View File

View File

@ -56,13 +56,11 @@ class Activitypub_explorer
{
$discovery = new Activitypub_explorer;
// Get valid Actor object
try {
$actor_profile = $discovery->lookup($url);
$actor_profile = $discovery->lookup($url);
if (!empty($actor_profile)) {
return $actor_profile[0];
} catch (Exception $e) {
throw new Exception('Invalid Actor.');
}
unset($discovery);
throw new Exception('Invalid Actor.');
}
/**
@ -168,10 +166,10 @@ class Activitypub_explorer
common_debug('ActivityPub Explorer: Unable to find a local Aprofile for '.$uri.' - looking for a Profile instead.');
// Well, maybe it is a pure blood?
// Iff, we are in the same instance:
$ACTIVITYPUB_BASE_INSTANCE_URI_length = strlen(ACTIVITYPUB_BASE_INSTANCE_URI);
if (substr($uri, 0, $ACTIVITYPUB_BASE_INSTANCE_URI_length) == ACTIVITYPUB_BASE_INSTANCE_URI) {
$ACTIVITYPUB_BASE_ACTOR_URI_length = strlen(ACTIVITYPUB_BASE_ACTOR_URI);
if (substr($uri, 0, $ACTIVITYPUB_BASE_ACTOR_URI_length) == ACTIVITYPUB_BASE_ACTOR_URI) {
try {
$profile = Profile::getByID(intval(substr($uri, $ACTIVITYPUB_BASE_INSTANCE_URI_length)));
$profile = Profile::getByID(intval(substr($uri, $ACTIVITYPUB_BASE_ACTOR_URI_length)));
common_debug('ActivityPub Explorer: Found a Profile for '.$uri);
// We found something!
$this->discovered_actor_profiles[]= $profile;
@ -215,7 +213,7 @@ class Activitypub_explorer
$res = $this->temp_res;
unset($this->temp_res);
}
if (isset($res['type']) && $res['type'] === 'OrderedCollection' && isset ($res['first'])) { // It's a potential collection of actors!!!
if (isset($res['type']) && $res['type'] === 'OrderedCollection' && isset($res['first'])) { // It's a potential collection of actors!!!
common_debug('ActivityPub Explorer: Found a collection of actors for '.$url);
$this->travel_collection($res['first']);
return true;
@ -275,14 +273,17 @@ class Activitypub_explorer
* Download and update given avatar image
*
* @author GNU Social
* @param string $url
* @return Avatar The Avatar we have on disk. (seldom used)
* @param Profile $profile
* @param string $url
* @return Avatar The Avatar we have on disk.
* @throws Exception in various failure cases
*/
private function _store_avatar($profile, $url)
private function _store_avatar(Profile $profile, $url)
{
if (!common_valid_http_url($url)) {
common_debug('ActivityPub Explorer: Started grabbing remote avatar from: '.$url);
if (!filter_var($url, FILTER_VALIDATE_URL)) {
// TRANS: Server exception. %s is a URL.
common_debug('ActivityPub Explorer: Failed because it is an invalid url: '.$url);
throw new ServerException(sprintf('Invalid avatar URL %s.'), $url);
}
@ -293,10 +294,12 @@ class Activitypub_explorer
$imgData = HTTPClient::quickGet($url);
// Make sure it's at least an image file. ImageFile can do the rest.
if (false === getimagesizefromstring($imgData)) {
common_debug('ActivityPub Explorer: Failed because the downloaded avatar: '.$url. 'is not a validad image.');
throw new UnsupportedMediaException('Downloaded avatar was not an image.');
}
file_put_contents($temp_filename, $imgData);
unset($imgData); // No need to carry this in memory.
common_debug('ActivityPub Explorer: Stored dowloaded avatar in: '.$temp_filename);
$id = $profile->getID();
@ -308,7 +311,9 @@ class Activitypub_explorer
common_timestamp()
);
rename($temp_filename, Avatar::path($filename));
common_debug('ActivityPub Explorer: Moved avatar from: '.$temp_filename.' to '.$filename);
} catch (Exception $e) {
common_debug('ActivityPub Explorer: Something went wrong while processing the avatar from: '.$url.' details: '.$e->getMessage());
unlink($temp_filename);
throw $e;
}
@ -326,6 +331,7 @@ class Activitypub_explorer
$profile->avatar = $url;
$profile->update($orig);
common_debug('ActivityPub Explorer: Seted Avatar from: '.$url.' to profile.');
return Avatar::getUploaded($profile);
}
@ -416,8 +422,7 @@ class Activitypub_explorer
$response = $client->get($url, $headers);
$res = json_decode($response->getBody(), true);
if (!isset($res['orderedItems']))
{
if (!isset($res['orderedItems'])) {
return false;
}