Add new admin debug module for ActivityPub
This commit is contained in:
parent
c26cc5b75e
commit
0a71495fa4
4 changed files with 170 additions and 0 deletions
|
@ -121,6 +121,7 @@ abstract class BaseAdmin extends BaseModule
|
|||
'webfinger' => ['webfinger' , DI::l10n()->t('check webfinger') , 'webfinger'],
|
||||
'itemsource' => ['admin/item/source' , DI::l10n()->t('Item Source') , 'itemsource'],
|
||||
'babel' => ['babel' , DI::l10n()->t('Babel') , 'babel'],
|
||||
'debug/ap' => ['debug/ap' , DI::l10n()->t('ActivityPub Conversion') , 'debug/ap'],
|
||||
]],
|
||||
];
|
||||
|
||||
|
|
144
src/Module/Debug/ActivityPubConversion.php
Normal file
144
src/Module/Debug/ActivityPubConversion.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2020, Friendica
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Debug;
|
||||
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Content\Text;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Tag;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Util\JsonLD;
|
||||
use Friendica\Util\XML;
|
||||
|
||||
class ActivityPubConversion extends BaseModule
|
||||
{
|
||||
public static function content(array $parameters = [])
|
||||
{
|
||||
function visible_whitespace($s)
|
||||
{
|
||||
return '<pre>' . htmlspecialchars($s) . '</pre>';
|
||||
}
|
||||
|
||||
$results = [];
|
||||
if (!empty($_REQUEST['source'])) {
|
||||
try {
|
||||
$source = json_decode($_REQUEST['source'], true);
|
||||
$trust_source = true;
|
||||
$uid = local_user();
|
||||
$push = false;
|
||||
|
||||
if (!$source) {
|
||||
throw new \Exception('Failed to decode source JSON');
|
||||
}
|
||||
|
||||
$formatted = json_encode($source, JSON_PRETTY_PRINT);
|
||||
$results[] = [
|
||||
'title' => DI::l10n()->t('Formatted'),
|
||||
'content' => visible_whitespace(trim(var_export($formatted, true), "'")),
|
||||
];
|
||||
$results[] = [
|
||||
'title' => DI::l10n()->t('Source'),
|
||||
'content' => visible_whitespace(var_export($source, true))
|
||||
];
|
||||
$activity = JsonLD::compact($source);
|
||||
if (!$activity) {
|
||||
throw new \Exception('Failed to compact JSON');
|
||||
}
|
||||
$results[] = [
|
||||
'title' => DI::l10n()->t('Activity'),
|
||||
'content' => visible_whitespace(var_export($activity, true))
|
||||
];
|
||||
|
||||
$type = JsonLD::fetchElement($activity, '@type');
|
||||
|
||||
if (!$type) {
|
||||
throw new \Exception('Empty type');
|
||||
}
|
||||
|
||||
if (!JsonLD::fetchElement($activity, 'as:object', '@id')) {
|
||||
throw new \Exception('Empty object');
|
||||
}
|
||||
|
||||
if (!JsonLD::fetchElement($activity, 'as:actor', '@id')) {
|
||||
throw new \Exception('Empty actor');
|
||||
}
|
||||
|
||||
// Don't trust the source if "actor" differs from "attributedTo". The content could be forged.
|
||||
if ($trust_source && ($type == 'as:Create') && is_array($activity['as:object'])) {
|
||||
$actor = JsonLD::fetchElement($activity, 'as:actor', '@id');
|
||||
$attributed_to = JsonLD::fetchElement($activity['as:object'], 'as:attributedTo', '@id');
|
||||
$trust_source = ($actor == $attributed_to);
|
||||
if (!$trust_source) {
|
||||
throw new \Exception('Not trusting actor: ' . $actor . '. It differs from attributedTo: ' . $attributed_to);
|
||||
}
|
||||
}
|
||||
|
||||
// $trust_source is called by reference and is set to true if the content was retrieved successfully
|
||||
$object_data = ActivityPub\Receiver::prepareObjectData($activity, $uid, $push, $trust_source);
|
||||
if (empty($object_data)) {
|
||||
throw new \Exception('No object data found');
|
||||
}
|
||||
|
||||
if (!$trust_source) {
|
||||
throw new \Exception('No trust for activity type "' . $type . '", so we quit now.');
|
||||
}
|
||||
|
||||
if (!empty($body) && empty($object_data['raw'])) {
|
||||
$object_data['raw'] = $body;
|
||||
}
|
||||
|
||||
// Internal flag for thread completion. See Processor.php
|
||||
if (!empty($activity['thread-completion'])) {
|
||||
$object_data['thread-completion'] = $activity['thread-completion'];
|
||||
}
|
||||
|
||||
$results[] = [
|
||||
'title' => DI::l10n()->t('Object data'),
|
||||
'content' => visible_whitespace(var_export($object_data, true))
|
||||
];
|
||||
|
||||
$item = ActivityPub\Processor::createItem($object_data);
|
||||
|
||||
$results[] = [
|
||||
'title' => DI::l10n()->t('Result Item'),
|
||||
'content' => visible_whitespace(var_export($item, true))
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
$results[] = [
|
||||
'title' => DI::l10n()->t('Error'),
|
||||
'content' => $e->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('debug/activitypubconversion.tpl');
|
||||
$o = Renderer::replaceMacros($tpl, [
|
||||
'$source' => ['source', DI::l10n()->t('Source activity'), $_REQUEST['source'] ?? '', ''],
|
||||
'$results' => $results
|
||||
]);
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
|
@ -107,6 +107,7 @@ return [
|
|||
'/apps' => [Module\Apps::class, [R::GET]],
|
||||
'/attach/{item:\d+}' => [Module\Attach::class, [R::GET]],
|
||||
'/babel' => [Module\Debug\Babel::class, [R::GET, R::POST]],
|
||||
'/debug/ap' => [Module\Debug\ActivityPubConversion::class, [R::GET, R::POST]],
|
||||
'/bookmarklet' => [Module\Bookmarklet::class, [R::GET]],
|
||||
|
||||
'/community[/{content}[/{accounttype}]]' => [Module\Conversation\Community::class, [R::GET]],
|
||||
|
|
24
view/templates/debug/activitypubconversion.tpl
Normal file
24
view/templates/debug/activitypubconversion.tpl
Normal file
|
@ -0,0 +1,24 @@
|
|||
<h2>ActivityPub Conversion</h2>
|
||||
<form action="debug/ap" method="post" class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
{{include file="field_textarea.tpl" field=$source}}
|
||||
</div>
|
||||
<p><button type="submit" class="btn btn-primary">Submit</button></p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{if $results}}
|
||||
<div class="babel-results">
|
||||
{{foreach $results as $result}}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{$result.title}}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{$result.content nofilter}}
|
||||
</div>
|
||||
</div>
|
||||
{{/foreach}}
|
||||
</div>
|
||||
{{/if}}
|
Loading…
Reference in a new issue