X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FUtil%2FJsonLD.php;h=0a4d5a0b55bf40808e891f81a1d832e0377ca3c1;hb=450c75300476942619bc350f4e80a5f658ffb24f;hp=ee5e0aea97cbb39666273f4b2f40e0638e4e21f3;hpb=4b4218f5162e11d1502bf49a12e6411e779a54df;p=friendica.git diff --git a/src/Util/JsonLD.php b/src/Util/JsonLD.php index ee5e0aea97..0a4d5a0b55 100644 --- a/src/Util/JsonLD.php +++ b/src/Util/JsonLD.php @@ -1,6 +1,6 @@ $url]); + break; + } + } + $recursion = 0; $x = debug_backtrace(); @@ -56,7 +84,7 @@ class JsonLD if ($recursion > 5) { Logger::error('jsonld bomb detected at: ' . $url); - exit(); + System::exit(); } $result = DI::cache()->get('documentLoader:' . $url); @@ -69,54 +97,6 @@ class JsonLD return $data; } - public static function removeSecurityLink(array $json) - { - if (!is_array($json['@context'])) { - return $json; - } - - if (($key = array_search('https://w3id.org/security/v1', $json['@context'])) !== false) { - unset($json['@context'][$key]); - $json['@context'] = array_values(array_filter($json['@context'])); - } - - return $json; - } - - public static function fixContext(array $json) - { - // Preparation for adding possibly missing content to the context - if (!empty($json['@context']) && is_string($json['@context'])) { - $json['@context'] = [$json['@context']]; - } - - if (($key = array_search('https://w3id.org/security/v1', $json['@context'])) !== false) { - unset($json['@context'][$key]); - $json['@context'] = array_values(array_filter($json['@context'])); - } - - $last_entry = count($json['@context']) - 1; - - $additional = [ - 'w3id' => 'https://w3id.org/security#', - 'signature' => 'w3id:signature', - 'RsaSignature2017' => 'w3id:RsaSignature2017', - 'created' => 'w3id:created', - 'creator' => 'w3id:creator', - 'nonce' => 'w3id:nonce', - 'signatureValue' => 'w3id:signatureValue', - 'publicKey' => 'w3id:publicKey', - 'publicKeyPem' => 'w3id:publicKeyPem']; - - if (is_array($json['@context'][$last_entry])) { - $json['@context'][$last_entry] = array_merge($json['@context'][$last_entry], $additional); - } else { - $json['@context'][] = $additional; - } - - return $json; - } - /** * Normalises a given JSON array * @@ -127,8 +107,6 @@ class JsonLD */ public static function normalize($json) { - $json = self::removeSecurityLink($json); - jsonld_set_document_loader('Friendica\Util\JsonLD::documentLoader'); $jsonobj = json_decode(json_encode($json, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); @@ -157,38 +135,17 @@ class JsonLD * Compacts a given JSON array * * @param array $json + * @param bool $logfailed * * @return array Compacted JSON array * @throws Exception */ - public static function compact($json) - { - $context = $json['@context'] ?? []; - $json['@context'] = ActivityPub::CONTEXT; - - $compacted = self::internalCompact($json); - if (empty($compacted)) { - Logger::info('Failed to compact with our context'); - $json['@context'] = $context; - $compacted = self::internalCompact($json); - if (empty($compacted)) { - Logger::info('Failed to compact with original context'); - } else { - Logger::info('Successful compacted with original context'); - } - } - - return $compacted; - } - - private static function internalCompact($json) + public static function compact($json, bool $logfailed = true): array { - $json = self::fixContext($json); - jsonld_set_document_loader('Friendica\Util\JsonLD::documentLoader'); $context = (object)['as' => 'https://www.w3.org/ns/activitystreams#', - 'w3id' => (object)['@id' => 'https://w3id.org/security#', '@type' => '@id'], + 'w3id' => 'https://w3id.org/security#', 'ldp' => (object)['@id' => 'http://www.w3.org/ns/ldp#', '@type' => '@id'], 'vcard' => (object)['@id' => 'http://www.w3.org/2006/vcard/ns#', '@type' => '@id'], 'dfrn' => (object)['@id' => 'http://purl.org/macgirvin/dfrn/1.0/', '@type' => '@id'], @@ -198,14 +155,43 @@ class JsonLD 'toot' => (object)['@id' => 'http://joinmastodon.org/ns#', '@type' => '@id'], 'litepub' => (object)['@id' => 'http://litepub.social/ns#', '@type' => '@id'], 'sc' => (object)['@id' => 'http://schema.org#', '@type' => '@id'], - 'pt' => (object)['@id' => 'https://joinpeertube.org/ns#', '@type' => '@id']]; + 'pt' => (object)['@id' => 'https://joinpeertube.org/ns#', '@type' => '@id'], + 'mobilizon' => (object)['@id' => 'https://joinmobilizon.org/ns#', '@type' => '@id'], + 'fedibird' => (object)['@id' => 'http://fedibird.com/ns#', '@type' => '@id'], + 'misskey' => (object)['@id' => 'https://misskey-hub.net/ns#', '@type' => '@id'], + ]; + + $orig_json = $json; - // Trying to avoid memory problems with large content fields - if (!empty($json['object']['source']['content'])) { - $content = $json['object']['source']['content']; - $json['object']['source']['content'] = ''; + // Preparation for adding possibly missing content to the context + if (!empty($json['@context']) && is_string($json['@context'])) { + $json['@context'] = [$json['@context']]; + } + + if (!empty($json['@context']) && is_array($json['@context'])) { + // Remove empty entries from the context (a problem with WriteFreely) + $json['@context'] = array_filter($json['@context']); + + // Workaround for servers with missing context + // See issue https://github.com/nextcloud/social/issues/330 + if (!in_array('https://w3id.org/security/v1', $json['@context'])) { + $json['@context'][] = 'https://w3id.org/security/v1'; + } + + // Issue 12419: Workaround for GoToSocial + $pos = array_search('http://joinmastodon.org/ns', $json['@context']); + if (is_int($pos)) { + $json['@context'][$pos] = ['toot' => 'http://joinmastodon.org/ns#']; + } } + // Bookwyrm transmits "id" fields with "null", which isn't allowed. + array_walk_recursive($json, function (&$value, $key) { + if ($key == 'id' && is_null($value)) { + $value = ''; + } + }); + $jsonobj = json_decode(json_encode($json, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); try { @@ -213,13 +199,19 @@ class JsonLD } catch (Exception $e) { $compacted = false; - Logger::error('compacting error', ['line' => $e->getLine(), 'message' => $e->getMessage(),'callstack' => System::callstack(20)]); + Logger::notice('compacting error', ['msg' => $e->getMessage(), 'previous' => $e->getPrevious(), 'line' => $e->getLine()]); + if ($logfailed && DI::config()->get('debug', 'ap_log_failure')) { + $tempfile = tempnam(System::getTempPath(), 'failed-jsonld'); + file_put_contents($tempfile, json_encode(['json' => $orig_json, 'callstack' => System::callstack(20), 'msg' => $e->getMessage(), 'previous' => $e->getPrevious()], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); + Logger::notice('Failed message stored', ['file' => $tempfile]); + } } $json = json_decode(json_encode($compacted, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), true); - if (isset($json['as:object']['as:source']['as:content']) && !empty($content)) { - $json['as:object']['as:source']['as:content'] = $content; + if ($json === false) { + Logger::notice('JSON encode->decode failed', ['orig_json' => $orig_json, 'compacted' => $compacted]); + $json = []; } return $json; @@ -241,7 +233,7 @@ class JsonLD } // If it isn't an array yet, make it to one - if (!is_int(key($array[$element]))) { + if (!is_array($array[$element]) || !is_int(key($array[$element]))) { $array[$element] = [$array[$element]]; }