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'],
|
'webfinger' => ['webfinger' , DI::l10n()->t('check webfinger') , 'webfinger'],
|
||||||
'itemsource' => ['admin/item/source' , DI::l10n()->t('Item Source') , 'itemsource'],
|
'itemsource' => ['admin/item/source' , DI::l10n()->t('Item Source') , 'itemsource'],
|
||||||
'babel' => ['babel' , DI::l10n()->t('Babel') , 'babel'],
|
'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]],
|
'/apps' => [Module\Apps::class, [R::GET]],
|
||||||
'/attach/{item:\d+}' => [Module\Attach::class, [R::GET]],
|
'/attach/{item:\d+}' => [Module\Attach::class, [R::GET]],
|
||||||
'/babel' => [Module\Debug\Babel::class, [R::GET, R::POST]],
|
'/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]],
|
'/bookmarklet' => [Module\Bookmarklet::class, [R::GET]],
|
||||||
|
|
||||||
'/community[/{content}[/{accounttype}]]' => [Module\Conversation\Community::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