From 771637459389d725ecb11e848740dce0f456418b Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sun, 20 Oct 2019 13:00:08 +0200 Subject: [PATCH 1/4] Move mod/receive to src/Module/Diaspora/receive - Added routes - Make Diaspora::decode(Raw) more explicit - Add new User::getByGuid() method --- mod/dfrn_notify.php | 6 +- mod/receive.php | 92 -------------------- src/Model/User.php | 22 ++++- src/Module/Diaspora/Receive.php | 146 ++++++++++++++++++++++++++++++++ src/Protocol/Diaspora.php | 14 +-- static/routes.config.php | 5 ++ 6 files changed, 182 insertions(+), 103 deletions(-) delete mode 100644 mod/receive.php create mode 100644 src/Module/Diaspora/Receive.php diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index dee6bad779..3d27593aaf 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); 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..521b8ea7fa --- /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\InternalServerErrorException('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['privKey'] ?? ''); + + 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 encoded.'); + 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]], From cbc48a4fd477d8d52d2e064a7223026e57f37917 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sun, 20 Oct 2019 13:23:13 +0200 Subject: [PATCH 2/4] Fix parameter --- mod/dfrn_notify.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index 3d27593aaf..46db319bc4 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -214,7 +214,7 @@ function dfrn_dispatch_public($postdata) function dfrn_dispatch_private($user, $postdata) { - $msg = Diaspora::decodeRaw($postdata, $user); + $msg = Diaspora::decodeRaw($postdata, $user['privKey'] ?? ''); if (!$msg) { System::xmlExit(4, 'Unable to parse message'); } From 2a41f0b104eadd0d1328b36c166459c7cfa96424 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Mon, 21 Oct 2019 11:34:47 +0200 Subject: [PATCH 3/4] wrong field --- mod/dfrn_notify.php | 2 +- src/Module/Diaspora/Receive.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index 46db319bc4..efe785d634 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -214,7 +214,7 @@ function dfrn_dispatch_public($postdata) function dfrn_dispatch_private($user, $postdata) { - $msg = Diaspora::decodeRaw($postdata, $user['privKey'] ?? ''); + $msg = Diaspora::decodeRaw($postdata, $user['prvkey'] ?? ''); if (!$msg) { System::xmlExit(4, 'Unable to parse message'); } diff --git a/src/Module/Diaspora/Receive.php b/src/Module/Diaspora/Receive.php index 521b8ea7fa..bb33a705d5 100644 --- a/src/Module/Diaspora/Receive.php +++ b/src/Module/Diaspora/Receive.php @@ -87,7 +87,7 @@ class Receive extends BaseModule $importer = User::getByGuid($guid); - $msg = self::decodePost(false, $importer['privKey'] ?? ''); + $msg = self::decodePost(false, $importer['prvkey'] ?? ''); self::$logger->info('Diaspora: Dispatching.'); From a25d841b85447d1c2be409f535d65b2c9202f324 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Mon, 21 Oct 2019 17:29:53 +0200 Subject: [PATCH 4/4] some improvements --- src/Module/Diaspora/Receive.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Module/Diaspora/Receive.php b/src/Module/Diaspora/Receive.php index bb33a705d5..978bccd833 100644 --- a/src/Module/Diaspora/Receive.php +++ b/src/Module/Diaspora/Receive.php @@ -51,7 +51,7 @@ class Receive extends BaseModule break; default: self::$logger->info('Wrong call.'); - throw new HTTPException\InternalServerErrorException('wrong call.'); + throw new HTTPException\BadRequestException('wrong call.'); break; } } @@ -134,7 +134,7 @@ class Receive extends BaseModule } } - self::$logger->info('Diaspora: Post encoded.'); + self::$logger->info('Diaspora: Post decoded.'); self::$logger->debug('Diaspora: Decoded message.', ['msg' => print_r($msg, true)]); if (!is_array($msg)) {