diff options
author | Bjoern Schiessle <bjoern@schiessle.org> | 2017-04-28 14:08:25 +0300 |
---|---|---|
committer | Bjoern Schiessle <bjoern@schiessle.org> | 2017-04-28 15:53:28 +0300 |
commit | e4f43f4930e3f5b8be625f636badf79aa59b3154 (patch) | |
tree | bad77ec53d04e6b5f95cd326ad1862f131975aba | |
parent | e46a8d2acbed6c61ce0568a3b5bedfba0a69efe2 (diff) |
make it more modular
Signed-off-by: Bjoern Schiessle <bjoern@schiessle.org>
-rw-r--r-- | server/lib/SignatureHandler.php | 88 | ||||
-rw-r--r-- | server/lib/UserManager.php | 121 | ||||
-rw-r--r-- | server/lib/Validator/Website.php | 91 | ||||
-rw-r--r-- | server/src/dependencies.php | 9 | ||||
-rw-r--r-- | server/vendor/composer/autoload_classmap.php | 2 | ||||
-rw-r--r-- | server/vendor/composer/autoload_static.php | 2 |
6 files changed, 221 insertions, 92 deletions
diff --git a/server/lib/SignatureHandler.php b/server/lib/SignatureHandler.php new file mode 100644 index 0000000..bf308d4 --- /dev/null +++ b/server/lib/SignatureHandler.php @@ -0,0 +1,88 @@ +<?php +/** + * @copyright Copyright (c) 2017 Bjoern Schiessle <bjoern@schiessle.org> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + + +namespace LookupServer; + +use GuzzleHttp\Client; + +class SignatureHandler { + + /** + * check signature of incoming request + * + * @param string $cloudId + * @param string $message + * @param string $signature + * @return bool + * @throws \Exception + */ + public function verify($cloudId, $message, $signature) { + // Get fed id + list($user, $host) = $this->splitCloudId($cloudId); + + // Retrieve public key && store + $ocsreq = new \GuzzleHttp\Psr7\Request( + 'GET', + 'http://'.$host . '/ocs/v2.php/identityproof/key/' . $user, + [ + 'OCS-APIREQUEST' => 'true', + 'Accept' => 'application/json', + ]); + + $client = new Client(); + $ocsresponse = $client->send($ocsreq, ['timeout' => 10]); + + $ocsresponse = json_decode($ocsresponse->getBody(), true); + + if ($ocsresponse === null || !isset($ocsresponse['ocs']) || + !isset($ocsresponse['ocs']['data']) || !isset($ocsresponse['ocs']['data']['public'])) { + throw new \BadMethodCallException(); + } + + $key = $ocsresponse['ocs']['data']['public']; + + // verify message + $message = json_encode($message); + $signature= base64_decode($signature); + + $res = openssl_verify($message, $signature, $key, OPENSSL_ALGO_SHA512); + + return $res === 1; + + } + + /** + * Split a cloud id in a user and host post + * + * @param $cloudId + * @return string[] + */ + private function splitCloudId($cloudId) { + $loc = strrpos($cloudId, '@'); + + $user = substr($cloudId, 0, $loc); + $host = substr($cloudId, $loc+1); + return [$user, $host]; + } + + +} diff --git a/server/lib/UserManager.php b/server/lib/UserManager.php index e6d2cbe..bf984c8 100644 --- a/server/lib/UserManager.php +++ b/server/lib/UserManager.php @@ -2,8 +2,8 @@ namespace LookupServer; -use GuzzleHttp\Client; use LookupServer\Validator\Email; +use LookupServer\Validator\Website; use \Psr\Http\Message\ServerRequestInterface as Request; use \Psr\Http\Message\ResponseInterface as Response; @@ -15,9 +15,28 @@ class UserManager { /** @var Email */ private $emailValidator; - public function __construct(\PDO $db, Email $emailValidator) { + /** @var Website */ + private $websiteValidator; + + /** @var SignatureHandler */ + private $signatureHandler; + + /** + * UserManager constructor. + * + * @param \PDO $db + * @param Email $emailValidator + * @param Website $websiteValidator + * @param SignatureHandler $signatureHandler + */ + public function __construct(\PDO $db, + Email $emailValidator, + Website $websiteValidator, + SignatureHandler $signatureHandler) { $this->db = $db; $this->emailValidator = $emailValidator; + $this->websiteValidator = $websiteValidator; + $this->signatureHandler = $signatureHandler; } public function search(Request $request, Response $response) { @@ -258,7 +277,7 @@ LIMIT 50'); $cloudId = $body['message']['data']['federationId']; try { - $verified = $this->verifyRequest($cloudId, $body['message'], $body['signature']); + $verified = $this->signatureHandler->verify($cloudId, $body['message'], $body['signature']); } catch(\Exception $e) { $response->withStatus(400); return $response; @@ -290,7 +309,7 @@ LIMIT 50'); $cloudId = $body['message']['data']['federationId']; try { - $verified = $this->verifyRequest($cloudId, $body['message'], $body['signature']); + $verified = $this->signatureHandler->verify($cloudId, $body['message'], $body['signature']); } catch(\Exception $e) { $response->withStatus(400); return $response; @@ -312,20 +331,21 @@ LIMIT 50'); public function verify(Request $request, Response $response) { $verificationRequests = $this->getOpenVerificationRequests(); - foreach ($verificationRequests as $verify) { + foreach ($verificationRequests as $verificationData) { $success = false; - switch ($verify['property']) { + switch ($verificationData['property']) { case 'twitter': //ToDo try to Verify Twitter account $success = $this->verifyTwitter(); break; case 'website': - $success = $this->verifyWebpage($verify); + $userData = $this->getForUserId($verificationData['userId']); + $success = $this->websiteValidator->verify($verificationData, $userData); break; } if ($success) { - $this->updateVerificationStatus($verify['storeId']); - $this->removeOpenVerificationRequest($verify['id']); + $this->updateVerificationStatus($verificationData['storeId']); + $this->removeOpenVerificationRequest($verificationData['id']); } } } @@ -377,94 +397,13 @@ LIMIT 50'); // ToDo get proof from twitter user $location // ToDo split $message & $signature // ToDo "verifyRequest" needs to be able to handle the shortened md5 signature from twitter - $result = $this->verifyRequest($cloudId, $message, $signature); + $result = $this->signatureHandler->verify($cloudId, $message, $signature); return result; } /** - * @param array $data - * @return bool - */ - private function verifyWebpage($data) { - $url = $this->getValidUrl($data['location']); - $proof = @file_get_contents($url); - $result = false; - if ($proof) { - $userData = $this->getForUserId($data['userId']); - $cloudId = $userData['federationId']; - $proofSanitized = trim(preg_replace('/\s\s+/', ' ', $proof)); - list($message, $signature) = $this->splitMessageSignature($proofSanitized); - $result = $this->verifyRequest($cloudId, $message, $signature); - } - - return $result; - } - - private function getValidUrl($url) { - $url = trim($url); - $url = rtrim($url, '/'); - if (strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) { - $url = 'http://' . $url; - } - - return $url . '/.well-known/CloudIdVerificationCode.txt'; - } - - private function splitMessageSignature($proof) { - $signature = substr($proof, -344); - $message = substr($proof, 0, -344); - - return [trim($message), trim($signature)]; - } - - /** - * check signature of incoming request - * - * @param string $cloudId - * @param string $message - * @param string $signature - * @return bool - * @throws \Exception - */ - protected function verifyRequest($cloudId, $message, $signature) { - // Get fed id - list($user, $host) = $this->splitCloudId($cloudId); - - // Retrieve public key && store - $ocsreq = new \GuzzleHttp\Psr7\Request( - 'GET', - 'http://'.$host . '/ocs/v2.php/identityproof/key/' . $user, - [ - 'OCS-APIREQUEST' => 'true', - 'Accept' => 'application/json', - ]); - - $client = new Client(); - $ocsresponse = $client->send($ocsreq, ['timeout' => 10]); - - $ocsresponse = json_decode($ocsresponse->getBody(), true); - - if ($ocsresponse === null || !isset($ocsresponse['ocs']) || - !isset($ocsresponse['ocs']['data']) || !isset($ocsresponse['ocs']['data']['public'])) { - throw new \BadMethodCallException(); - } - - $key = $ocsresponse['ocs']['data']['public']; - - // verify message - $message = json_encode($message); - $signature= base64_decode($signature); - - $res = openssl_verify($message, $signature, $key, OPENSSL_ALGO_SHA512); - - return $res === 1; - - } - - - /** * @param string $cloudId * @param string[] $data * @param int $timestamp diff --git a/server/lib/Validator/Website.php b/server/lib/Validator/Website.php new file mode 100644 index 0000000..e43bfb0 --- /dev/null +++ b/server/lib/Validator/Website.php @@ -0,0 +1,91 @@ +<?php +/** + * @copyright Copyright (c) 2017 Bjoern Schiessle <bjoern@schiessle.org> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + + +namespace LookupServer\Validator; + + +use LookupServer\SignatureHandler; + +class Website { + + /** @var SignatureHandler */ + private $signatureHandler; + + public function __construct(SignatureHandler $signatureHandler) { + $this->signatureHandler = $signatureHandler; + } + + /** + * verify website proof + * + * @param array $verificationData from toVerify table + * @param array $userData stored user data + * @return bool + */ + public function verify($verificationData, $userData) { + $url = $this->getValidUrl($verificationData['location']); + $proof = @file_get_contents($url); + $result = false; + try { + if ($proof) { + $cloudId = $userData['federationId']; + $proofSanitized = trim(preg_replace('/\s\s+/', ' ', $proof)); + list($message, $signature) = $this->splitMessageSignature($proofSanitized); + $result = $this->signatureHandler->verify($cloudId, $message, $signature); + } + } catch (\Exception $e) { + // do nothing, just return false + } + + return $result; + } + + /** + * construct valid URL to proof + * + * @param string $url + * @return string + */ + private function getValidUrl($url) { + $url = trim($url); + $url = rtrim($url, '/'); + if (strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) { + $url = 'http://' . $url; + } + + return $url . '/.well-known/CloudIdVerificationCode.txt'; + } + + /** + * split message and signature + * + * @param string $proof + * @return array + */ + private function splitMessageSignature($proof) { + $signature = substr($proof, -344); + $message = substr($proof, 0, -344); + + return [trim($message), trim($signature)]; + } + +} diff --git a/server/src/dependencies.php b/server/src/dependencies.php index 0e95274..38e7fc4 100644 --- a/server/src/dependencies.php +++ b/server/src/dependencies.php @@ -9,7 +9,10 @@ $container['db'] = function($c) { return $pdo; }; $container['UserManager'] = function($c) { - return new \LookupServer\UserManager($c->db, $c->EmailValidator); + return new \LookupServer\UserManager($c->db, $c->EmailValidator, $c->WebsiteValidator, $c->SignatureHandler); +}; +$container['SignatureHandler'] = function($c) { + return new \LookupServer\SignatureHandler(); }; $container['EmailValidator'] = function($c) { return new \LookupServer\Validator\Email( @@ -19,6 +22,10 @@ $container['EmailValidator'] = function($c) { $c->settings['emailfrom'] ); }; +$container['WebsiteValidator'] = function($c) { + return new \LookupServer\Validator\Website($c->SignatureHandler); +}; + $container['Status'] = function($c) { return new \LookupServer\Status(); }; diff --git a/server/vendor/composer/autoload_classmap.php b/server/vendor/composer/autoload_classmap.php index 071a334..0c0d91d 100644 --- a/server/vendor/composer/autoload_classmap.php +++ b/server/vendor/composer/autoload_classmap.php @@ -107,9 +107,11 @@ return array( 'Interop\\Container\\Exception\\NotFoundException' => $vendorDir . '/container-interop/container-interop/src/Interop/Container/Exception/NotFoundException.php', 'LookupServer\\BruteForceMiddleware' => $baseDir . '/lib/BruteForceMiddleware.php', 'LookupServer\\Replication' => $baseDir . '/lib/Replication.php', + 'LookupServer\\SignatureHandler' => $baseDir . '/lib/SignatureHandler.php', 'LookupServer\\Status' => $baseDir . '/lib/Status.php', 'LookupServer\\UserManager' => $baseDir . '/lib/UserManager.php', 'LookupServer\\Validator\\Email' => $baseDir . '/lib/Validator/Email.php', + 'LookupServer\\Validator\\Website' => $baseDir . '/lib/Validator/Website.php', 'Pimple\\Container' => $vendorDir . '/pimple/pimple/src/Pimple/Container.php', 'Pimple\\ServiceProviderInterface' => $vendorDir . '/pimple/pimple/src/Pimple/ServiceProviderInterface.php', 'Pimple\\Tests\\Fixtures\\Invokable' => $vendorDir . '/pimple/pimple/src/Pimple/Tests/Fixtures/Invokable.php', diff --git a/server/vendor/composer/autoload_static.php b/server/vendor/composer/autoload_static.php index 9e6a83d..9726f0f 100644 --- a/server/vendor/composer/autoload_static.php +++ b/server/vendor/composer/autoload_static.php @@ -202,9 +202,11 @@ class ComposerStaticInit509ee4e79733fbe3199b97373b795eca 'Interop\\Container\\Exception\\NotFoundException' => __DIR__ . '/..' . '/container-interop/container-interop/src/Interop/Container/Exception/NotFoundException.php', 'LookupServer\\BruteForceMiddleware' => __DIR__ . '/../..' . '/lib/BruteForceMiddleware.php', 'LookupServer\\Replication' => __DIR__ . '/../..' . '/lib/Replication.php', + 'LookupServer\\SignatureHandler' => __DIR__ . '/../..' . '/lib/SignatureHandler.php', 'LookupServer\\Status' => __DIR__ . '/../..' . '/lib/Status.php', 'LookupServer\\UserManager' => __DIR__ . '/../..' . '/lib/UserManager.php', 'LookupServer\\Validator\\Email' => __DIR__ . '/../..' . '/lib/Validator/Email.php', + 'LookupServer\\Validator\\Website' => __DIR__ . '/../..' . '/lib/Validator/Website.php', 'Pimple\\Container' => __DIR__ . '/..' . '/pimple/pimple/src/Pimple/Container.php', 'Pimple\\ServiceProviderInterface' => __DIR__ . '/..' . '/pimple/pimple/src/Pimple/ServiceProviderInterface.php', 'Pimple\\Tests\\Fixtures\\Invokable' => __DIR__ . '/..' . '/pimple/pimple/src/Pimple/Tests/Fixtures/Invokable.php', |