diff --git a/src/Util/JsonLD.php b/src/Util/JsonLD.php index ee5e0aea97..c20d4846bf 100644 --- a/src/Util/JsonLD.php +++ b/src/Util/JsonLD.php @@ -69,49 +69,14 @@ class JsonLD return $data; } - public static function removeSecurityLink(array $json) + private static function replaceSecurityLink(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; + $json['@context'][$key] = DI::baseUrl() . '/static/w3id-security-v1.json'; } return $json; @@ -127,7 +92,7 @@ class JsonLD */ public static function normalize($json) { - $json = self::removeSecurityLink($json); + $json = self::replaceSecurityLink($json); jsonld_set_document_loader('Friendica\Util\JsonLD::documentLoader'); @@ -163,32 +128,23 @@ class JsonLD */ public static function compact($json) { - $context = $json['@context'] ?? []; - $json['@context'] = ActivityPub::CONTEXT; - - $compacted = self::internalCompact($json); + $compacted = self::internalCompact($json, false); 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'); - } + $json['@context'] = ActivityPub::CONTEXT; + $compacted = self::internalCompact($json, true); } return $compacted; } - private static function internalCompact($json) + private static function internalCompact($json, bool $error_log) { - $json = self::fixContext($json); + $json = self::replaceSecurityLink($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'], @@ -200,6 +156,17 @@ class JsonLD 'sc' => (object)['@id' => 'http://schema.org#', '@type' => '@id'], 'pt' => (object)['@id' => 'https://joinpeertube.org/ns#', '@type' => '@id']]; + // Preparation for adding possibly missing content to the context + if (!empty($json['@context']) && is_string($json['@context'])) { + $json['@context'] = [$json['@context']]; + } + + // Workaround for servers with missing context + // See issue https://github.com/nextcloud/social/issues/330 + if (!empty($json['@context']) && is_array($json['@context'])) { + $json['@context'][] = DI::baseUrl() . '/static/w3id-security-v1.json'; + } + // Trying to avoid memory problems with large content fields if (!empty($json['object']['source']['content'])) { $content = $json['object']['source']['content']; @@ -213,7 +180,9 @@ class JsonLD } catch (Exception $e) { $compacted = false; - Logger::error('compacting error', ['line' => $e->getLine(), 'message' => $e->getMessage(),'callstack' => System::callstack(20)]); + if ($error_log) { + Logger::error('compacting error', ['line' => $e->getLine(), 'message' => $e->getMessage(),'callstack' => System::callstack(20)]); + } } $json = json_decode(json_encode($compacted, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), true); diff --git a/src/Util/LDSignature.php b/src/Util/LDSignature.php index dcbb9ccae3..f51756633c 100644 --- a/src/Util/LDSignature.php +++ b/src/Util/LDSignature.php @@ -57,7 +57,7 @@ class LDSignature $dhash = self::hash(self::signableData($data)); $x = Crypto::rsaVerify($ohash . $dhash, base64_decode($data['signature']['signatureValue']), $pubkey); - Logger::log('LD-verify: ' . intval($x)); + Logger::notice('LD-verify', ['verified' => (int)$x, 'actor' => $profile['url']]); if (empty($x)) { return false; diff --git a/static/w3id-security-v1.json b/static/w3id-security-v1.json new file mode 100644 index 0000000000..765650d348 --- /dev/null +++ b/static/w3id-security-v1.json @@ -0,0 +1,49 @@ +{ + "@context": { + "id": "@id", + "type": "@type", + + "dc": "http://purl.org/dc/terms/", + "sec": "https://w3id.org/security#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "EcdsaKoblitzSignature2016": "sec:EcdsaKoblitzSignature2016", + "Ed25519Signature2018": "sec:Ed25519Signature2018", + "EncryptedMessage": "sec:EncryptedMessage", + "GraphSignature2012": "sec:GraphSignature2012", + "LinkedDataSignature2015": "sec:LinkedDataSignature2015", + "LinkedDataSignature2016": "sec:LinkedDataSignature2016", + "CryptographicKey": "sec:Key", + + "authenticationTag": "sec:authenticationTag", + "canonicalizationAlgorithm": "sec:canonicalizationAlgorithm", + "cipherAlgorithm": "sec:cipherAlgorithm", + "cipherData": "sec:cipherData", + "cipherKey": "sec:cipherKey", + "created": {"@id": "dc:created", "@type": "xsd:dateTime"}, + "creator": {"@id": "dc:creator", "@type": "@id"}, + "digestAlgorithm": "sec:digestAlgorithm", + "digestValue": "sec:digestValue", + "domain": "sec:domain", + "encryptionKey": "sec:encryptionKey", + "expiration": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "initializationVector": "sec:initializationVector", + "iterationCount": "sec:iterationCount", + "nonce": "sec:nonce", + "normalizationAlgorithm": "sec:normalizationAlgorithm", + "owner": {"@id": "sec:owner", "@type": "@id"}, + "password": "sec:password", + "privateKey": {"@id": "sec:privateKey", "@type": "@id"}, + "privateKeyPem": "sec:privateKeyPem", + "publicKey": {"@id": "sec:publicKey", "@type": "@id"}, + "publicKeyBase58": "sec:publicKeyBase58", + "publicKeyPem": "sec:publicKeyPem", + "publicKeyService": {"@id": "sec:publicKeyService", "@type": "@id"}, + "revoked": {"@id": "sec:revoked", "@type": "xsd:dateTime"}, + "salt": "sec:salt", + "signature": "sec:signature", + "signatureAlgorithm": "sec:signingAlgorithm", + "signatureValue": "sec:signatureValue" + } + } \ No newline at end of file