3 * @copyright Copyright (C) 2010-2022, the Friendica project
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Module\Debug;
24 use Friendica\BaseModule;
25 use Friendica\Core\Renderer;
27 use Friendica\Protocol\ActivityPub;
28 use Friendica\Util\JsonLD;
30 class ActivityPubConversion extends BaseModule
32 protected function content(array $request = []): string
34 function visible_whitespace($s)
36 return '<pre>' . htmlspecialchars($s) . '</pre>';
40 if (!empty($_REQUEST['source'])) {
42 $source = json_decode($_REQUEST['source'], true);
44 $uid = DI::userSession()->getLocalUserId();
48 throw new \Exception('Failed to decode source JSON');
51 $formatted = json_encode($source, JSON_PRETTY_PRINT);
53 'title' => DI::l10n()->t('Formatted'),
54 'content' => visible_whitespace(trim(var_export($formatted, true), "'")),
57 'title' => DI::l10n()->t('Source'),
58 'content' => visible_whitespace(var_export($source, true))
60 $activity = JsonLD::compact($source);
62 throw new \Exception('Failed to compact JSON');
65 'title' => DI::l10n()->t('Activity'),
66 'content' => visible_whitespace(var_export($activity, true))
69 $type = JsonLD::fetchElement($activity, '@type');
72 throw new \Exception('Empty type');
75 if (!JsonLD::fetchElement($activity, 'as:object', '@id')) {
76 throw new \Exception('Empty object');
79 if (!JsonLD::fetchElement($activity, 'as:actor', '@id')) {
80 throw new \Exception('Empty actor');
83 // Don't trust the source if "actor" differs from "attributedTo". The content could be forged.
84 if ($trust_source && ($type == 'as:Create') && is_array($activity['as:object'])) {
85 $actor = JsonLD::fetchElement($activity, 'as:actor', '@id');
86 $attributed_to = JsonLD::fetchElement($activity['as:object'], 'as:attributedTo', '@id');
87 $trust_source = ($actor == $attributed_to);
89 throw new \Exception('Not trusting actor: ' . $actor . '. It differs from attributedTo: ' . $attributed_to);
93 // $trust_source is called by reference and is set to true if the content was retrieved successfully
94 $object_data = ActivityPub\Receiver::prepareObjectData($activity, $uid, $push, $trust_source);
95 if (empty($object_data)) {
96 throw new \Exception('No object data found');
100 throw new \Exception('No trust for activity type "' . $type . '", so we quit now.');
103 if (!empty($body) && empty($object_data['raw'])) {
104 $object_data['raw'] = $body;
107 // Internal flag for thread completion. See Processor.php
108 if (!empty($activity['thread-completion'])) {
109 $object_data['thread-completion'] = $activity['thread-completion'];
112 if (!empty($activity['completion-mode'])) {
113 $object_data['completion-mode'] = $activity['completion-mode'];
117 'title' => DI::l10n()->t('Object data'),
118 'content' => visible_whitespace(var_export($object_data, true))
121 $item = ActivityPub\Processor::createItem($object_data, true);
124 'title' => DI::l10n()->t('Result Item'),
125 'content' => visible_whitespace(var_export($item, true))
127 } catch (\Throwable $e) {
129 'title' => DI::l10n()->tt('Error', 'Errors', 1),
130 'content' => $e->getMessage(),
135 $tpl = Renderer::getMarkupTemplate('debug/activitypubconversion.tpl');
136 $o = Renderer::replaceMacros($tpl, [
137 '$title' => DI::l10n()->t('ActivityPub Conversion'),
138 '$source' => ['source', DI::l10n()->t('Source activity'), $_REQUEST['source'] ?? '', ''],
139 '$results' => $results,
140 '$submit' => DI::l10n()->t('Submit'),