diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index dee6bad779..efe785d634 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -15,8 +15,8 @@ use Friendica\Model\Contact; use Friendica\Model\User; use Friendica\Protocol\DFRN; use Friendica\Protocol\Diaspora; -use Friendica\Util\Strings; use Friendica\Util\Network; +use Friendica\Util\Strings; function dfrn_notify_post(App $a) { Logger::log(__function__, Logger::TRACE); @@ -184,7 +184,7 @@ function dfrn_notify_post(App $a) { function dfrn_dispatch_public($postdata) { - $msg = Diaspora::decodeRaw([], $postdata, true); + $msg = Diaspora::decodeRaw($postdata, '', true); if (!$msg) { // We have to fail silently to be able to hand it over to the salmon parser return false; @@ -214,7 +214,7 @@ function dfrn_dispatch_public($postdata) function dfrn_dispatch_private($user, $postdata) { - $msg = Diaspora::decodeRaw($user, $postdata); + $msg = Diaspora::decodeRaw($postdata, $user['prvkey'] ?? ''); if (!$msg) { System::xmlExit(4, 'Unable to parse message'); } diff --git a/mod/receive.php b/mod/receive.php deleted file mode 100644 index 182a1df8c5..0000000000 --- a/mod/receive.php +++ /dev/null @@ -1,92 +0,0 @@ -argc == 2) && ($a->argv[1] === 'public')) { - $public = true; - $importer = []; - } else { - $public = false; - - if ($a->argc != 3 || $a->argv[1] !== 'users') { - throw new \Friendica\Network\HTTPException\InternalServerErrorException(); - } - $guid = $a->argv[2]; - - $importer = DBA::selectFirst('user', [], ['guid' => $guid, 'account_expired' => false, 'account_removed' => false]); - if (!DBA::isResult($importer)) { - throw new \Friendica\Network\HTTPException\InternalServerErrorException(); - } - } - - // It is an application/x-www-form-urlencoded - - Logger::log('mod-diaspora: receiving post', Logger::DEBUG); - - if (empty($_POST['xml'])) { - $postdata = Network::postdata(); - if ($postdata == '') { - throw new \Friendica\Network\HTTPException\InternalServerErrorException(); - } - - Logger::log('mod-diaspora: message is in the new format', Logger::DEBUG); - $msg = Diaspora::decodeRaw($importer, $postdata); - } else { - $xml = urldecode($_POST['xml']); - - Logger::log('mod-diaspora: decode message in the old format', Logger::DEBUG); - $msg = Diaspora::decode($importer, $xml); - - if ($public && !$msg) { - Logger::log('mod-diaspora: decode message in the new format', Logger::DEBUG); - $msg = Diaspora::decodeRaw($importer, $xml); - } - } - - Logger::log('mod-diaspora: decoded', Logger::DEBUG); - - Logger::log('mod-diaspora: decoded msg: ' . print_r($msg, true), Logger::DATA); - - if (!is_array($msg)) { - throw new \Friendica\Network\HTTPException\InternalServerErrorException(); - } - - Logger::log('mod-diaspora: dispatching', Logger::DEBUG); - - $ret = true; - if ($public) { - Diaspora::dispatchPublic($msg); - } else { - $ret = Diaspora::dispatch($importer, $msg); - } - - if ($ret) { - throw new \Friendica\Network\HTTPException\OKException(); - } else { - throw new \Friendica\Network\HTTPException\InternalServerErrorException(); - } -} diff --git a/src/Model/User.php b/src/Model/User.php index ef49f45eda..499c55330b 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -18,7 +18,6 @@ use Friendica\Core\Protocol; use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; -use Friendica\Model\Photo; use Friendica\Model\TwoFactor\AppSpecificPassword; use Friendica\Object\Image; use Friendica\Util\Crypto; @@ -105,6 +104,27 @@ class User return DBA::selectFirst('user', $fields, ['uid' => $uid]); } + /** + * Returns a user record based on it's GUID + * + * @param string $guid The guid of the user + * @param array $fields The fields to retrieve + * @param bool $active True, if only active records are searched + * + * @return array|boolean User record if it exists, false otherwise + * @throws Exception + */ + public static function getByGuid(string $guid, array $fields = [], bool $active = true) + { + if ($active) { + $cond = ['guid' => $guid, 'account_expired' => false, 'account_removed' => false]; + } else { + $cond = ['guid' => $guid]; + } + + return DBA::selectFirst('user', $fields, $cond); + } + /** * @param string $nickname * @param array $fields diff --git a/src/Module/Diaspora/Receive.php b/src/Module/Diaspora/Receive.php new file mode 100644 index 0000000000..978bccd833 --- /dev/null +++ b/src/Module/Diaspora/Receive.php @@ -0,0 +1,146 @@ +get('system', 'diaspora_enabled', false); + if (!$enabled) { + self::$logger->info('Diaspora disabled.'); + throw new HTTPException\InternalServerErrorException('Diaspora disabled.'); + } + + /** @var App\Arguments $args */ + $args = self::getClass(App\Arguments::class); + + $type = $args->get(1); + + switch ($type) { + case 'public': + self::receivePublic(); + break; + case 'users': + self::receiveUser($args->get(2)); + break; + default: + self::$logger->info('Wrong call.'); + throw new HTTPException\BadRequestException('wrong call.'); + break; + } + } + + /** + * Receive a public Diaspora posting + * + * @throws HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + private static function receivePublic() + { + self::$logger->info('Diaspora: Receiving post.'); + + $msg = self::decodePost(); + + self::$logger->info('Diaspora: Dispatching.'); + + Diaspora::dispatchPublic($msg); + } + + /** + * Receive a Diaspora posting for a user + * + * @param string $guid The GUID of the importer + * + * @throws HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + private static function receiveUser(string $guid) + { + self::$logger->info('Diaspora: Receiving post.'); + + $importer = User::getByGuid($guid); + + $msg = self::decodePost(false, $importer['prvkey'] ?? ''); + + self::$logger->info('Diaspora: Dispatching.'); + + if (Diaspora::dispatch($importer, $msg)) { + throw new HTTPException\OKException(); + } else { + throw new HTTPException\InternalServerErrorException(); + } + } + + /** + * Decodes a Diaspora message based on the posted data + * + * @param string $privKey The private key of the importer + * @param bool $public True, if the post is public + * + * @return array + * @throws HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + private static function decodePost(bool $public = true, string $privKey = '') + { + if (empty($_POST['xml'])) { + + $postdata = Network::postdata(); + + if (empty($postdata)) { + throw new HTTPException\InternalServerErrorException('Missing postdata.'); + } + + self::$logger->info('Diaspora: Message is in the new format.'); + + $msg = Diaspora::decodeRaw($postdata, $privKey); + } else { + + $xml = urldecode($_POST['xml']); + + self::$logger->info('Diaspora: Decode message in the old format.'); + $msg = Diaspora::decode($xml, $privKey); + + if ($public && !$msg) { + self::$logger->info('Diaspora: Decode message in the new format.'); + $msg = Diaspora::decodeRaw($xml, $privKey); + } + } + + self::$logger->info('Diaspora: Post decoded.'); + self::$logger->debug('Diaspora: Decoded message.', ['msg' => print_r($msg, true)]); + + if (!is_array($msg)) { + throw new HTTPException\InternalServerErrorException('Message is not an array.'); + } + + return $msg; + } +} diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 587b34c3fe..aec3a283f8 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -413,8 +413,8 @@ class Diaspora /** * @brief: Decodes incoming Diaspora message in the new format * - * @param array $importer Array of the importer user * @param string $raw raw post message + * @param string $privKey The private key of the importer * @param boolean $no_exit Don't do an http exit on error * * @return array @@ -424,7 +424,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function decodeRaw(array $importer, $raw, $no_exit = false) + public static function decodeRaw(string $raw, string $privKey = '', bool $no_exit = false) { $data = json_decode($raw); @@ -434,7 +434,7 @@ class Diaspora $ciphertext = base64_decode($data->encrypted_magic_envelope); $outer_key_bundle = ''; - @openssl_private_decrypt($encrypted_aes_key_bundle, $outer_key_bundle, $importer['prvkey']); + @openssl_private_decrypt($encrypted_aes_key_bundle, $outer_key_bundle, $privKey); $j_outer_key_bundle = json_decode($outer_key_bundle); if (!is_object($j_outer_key_bundle)) { @@ -519,8 +519,8 @@ class Diaspora /** * @brief: Decodes incoming Diaspora message in the deprecated format * - * @param array $importer Array of the importer user * @param string $xml urldecoded Diaspora salmon + * @param string $privKey The private key of the importer * * @return array * 'message' -> decoded Diaspora XML message @@ -529,7 +529,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function decode(array $importer, $xml) + public static function decode(string $xml, string $privKey = '') { $public = false; $basedom = XML::parseString($xml); @@ -548,7 +548,7 @@ class Diaspora $author_link = str_replace('acct:', '', $children->header->author_id); } else { // This happens with posts from a relais - if (!$importer) { + if (empty($privKey)) { Logger::log("This is no private post in the old format", Logger::DEBUG); return false; } @@ -559,7 +559,7 @@ class Diaspora $ciphertext = base64_decode($encrypted_header->ciphertext); $outer_key_bundle = ''; - openssl_private_decrypt($encrypted_aes_key_bundle, $outer_key_bundle, $importer['prvkey']); + openssl_private_decrypt($encrypted_aes_key_bundle, $outer_key_bundle, $privKey); $j_outer_key_bundle = json_decode($outer_key_bundle); diff --git a/static/routes.config.php b/static/routes.config.php index 0601d8e41d..7cc9fdaa6d 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -196,6 +196,11 @@ return [ '/saved/remove' => [Module\Search\Saved::class, [R::GET]], ], + '/receive' => [ + '/public' => [Module\Diaspora\Receive::class, [R::POST]], + '/users/{guid}' => [Module\Diaspora\Receive::class, [R::POST]], + ], + '/settings' => [ '/2fa' => [ '[/]' => [Module\Settings\TwoFactor\Index::class, [R::GET, R::POST]],