--- /dev/null
+<?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;
+ }
+}