diff options
author | Björn Schießle <bjoern@schiessle.org> | 2017-03-03 14:50:32 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-03 14:50:32 +0300 |
commit | cd051fc1062f5e3feee3230fa1069f9a64af2028 (patch) | |
tree | cb6e14c3c2013dd5e7f2908ef9203059e0a34269 | |
parent | 386ae4a3e571ec4f7d5abde54e69fbed35090d02 (diff) | |
parent | 5ac35b822c6ab679cac37885affa9fb5dd001985 (diff) |
Merge pull request #9 from nextcloud/add-delete
Add delete
-rwxr-xr-x | doc/architecture.md | 14 | ||||
-rw-r--r-- | server/index.php | 1 | ||||
-rw-r--r-- | server/lib/UserManager.php | 151 |
3 files changed, 122 insertions, 44 deletions
diff --git a/doc/architecture.md b/doc/architecture.md index 80ae78c..32f0b82 100755 --- a/doc/architecture.md +++ b/doc/architecture.md @@ -32,7 +32,7 @@ calls. The following REST calls exists: This can be used by a user to create a record and initially publish their own information. -Endpoint: http://dev/nextcloud/lookup-server/server/ +Endpoint: http://dev/nextcloud/lookup-server/server/users Method: POST Data: JSON blob @@ -61,7 +61,7 @@ Updating a record is the same as publishing a new record. Unchanged fields will not be touched. New fields will be added (and if possible verified). And fields no longer in the update request will be removed. -Endpoint: http://dev/nextcloud/lookup-server/server/ +Endpoint: http://dev/nextcloud/lookup-server/server/users Method: POST Data: JSON blob @@ -88,8 +88,8 @@ Data: JSON blob ### Delete user Deleting is simply removing all additional info. -Endpoint: http://dev/nextcloud/lookup-server/server/ -Method: POST +Endpoint: http://dev/nextcloud/lookup-server/server/users +Method:DELETE Data: JSON blob ``` @@ -106,13 +106,13 @@ Data: JSON blob } ``` -Note that a database entry will still remain on the lookup server. In order to -properly propagat this. +Note the server will still keep the cloud id in order to properly propagate this. +But all other personal data will be removed. ### Search users This call can be used to search for a user in a fuzzy way Example: -curl -X GET http://dev/nextcloud/lookup-server/server/?search=searchstring +curl -X GET http://dev/nextcloud/lookup-server/server/users?search=searchstring ### Get replication log This call is used for master-master replication between different nodes. diff --git a/server/index.php b/server/index.php index 59129d4..de9c028 100644 --- a/server/index.php +++ b/server/index.php @@ -18,6 +18,7 @@ $app->add($container->get('BruteForceMiddleware')); $app->get('/users', 'UserManager:search'); $app->post('/users', 'UserManager:register'); +$app->delete('/users', 'UserManager:delete'); $app->get('/validate/email/{token}', 'EmailValidator:validate')->setName('validateEmail'); $app->get('/status', 'Status:status'); diff --git a/server/lib/UserManager.php b/server/lib/UserManager.php index ef24616..8c995d5 100644 --- a/server/lib/UserManager.php +++ b/server/lib/UserManager.php @@ -3,7 +3,6 @@ namespace LookupServer; use GuzzleHttp\Client; -use GuzzleHttp\Exception\RequestException; use LookupServer\Validator\Email; use \Psr\Http\Message\ServerRequestInterface as Request; use \Psr\Http\Message\ResponseInterface as Response; @@ -221,43 +220,14 @@ LIMIT 50'); $cloudId = $body['message']['data']['federationId']; - // Get fed id - list($user, $host) = $this->splitCloudId($cloudId); - - // Retrieve public key && store - $ocsreq = new \GuzzleHttp\Psr7\Request( - 'GET', - 'https://'.$host . '/ocs/v2.php/identityproof/key/' . $user, - [ - 'OCS-APIREQUEST' => 'true', - 'Accept' => 'application/json', - ]); - - $client = new Client(); try { - $ocsresponse = $client->send($ocsreq, ['timeout' => 10]); - } catch(RequestException $e) { - $response->withStatus(400); - return $response; - } - - $ocsresponse = json_decode($ocsresponse->getBody(), true); + $verified = $this->verifyRequest($cloudId, $body['message'], $body['signature']); + } catch(\Exception $e) { + $response->withStatus(400); + return $response; + } - if ($ocsresponse === null || !isset($ocsresponse['ocs']) || - !isset($ocsresponse['ocs']['data']) || !isset($ocsresponse['ocs']['data']['public'])) { - $response->withStatus(400); - return $response; - } - - $key = $ocsresponse['ocs']['data']['public']; - - // verify message - $message = json_encode($body['message']); - $signature= base64_decode($body['signature']); - - $res = openssl_verify($message, $signature, $key, OPENSSL_ALGO_SHA512); - - if ($res === 1) { + if ($verified) { $result = $this->insertOrUpdate($cloudId, $body['message']['data'], $body['message']['timestamp']); if ($result === false) { $response->withStatus(403); @@ -270,7 +240,85 @@ LIMIT 50'); return $response; } - /** + public function delete(Request $request, Response $response) { + $body = json_decode($request->getBody(), true); + + if ($body === null || !isset($body['message']) || !isset($body['message']['data']) || + !isset($body['message']['data']['federationId']) || !isset($body['signature']) || + !isset($body['message']['timestamp'])) { + $response->withStatus(400); + return $response; + } + + $cloudId = $body['message']['data']['federationId']; + + try { + $verified = $this->verifyRequest($cloudId, $body['message'], $body['signature']); + } catch(\Exception $e) { + $response->withStatus(400); + return $response; + } + + + if ($verified) { + $result = $this->deleteDBRecord($cloudId); + if ($result === false) { + $response->withStatus(404); + } + } else { + // ERROR OUT + $response->withStatus(403); + } + + return $response; + } + + /** + * 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 @@ -300,4 +348,33 @@ LIMIT 50'); return true; } + + /** + * Delete all personal data. We keep the basic user entry with the + * federated cloud ID in order to propagate the changes + * + * @param string $cloudId + * @return bool + */ + private function deleteDBRecord($cloudId) { + + $stmt = $this->db->prepare('SELECT * FROM users WHERE federationId = :federationId'); + $stmt->bindParam(':federationId', $cloudId); + $stmt->execute(); + $row = $stmt->fetch(); + $stmt->closeCursor(); + + // If we can't find the user + if ($row === false) { + return false; + } + + // delete user data + $stmt = $this->db->prepare('DELETE FROM store WHERE userId = :userId'); + $stmt->bindParam(':userId', $row['id']); + $stmt->execute(); + $stmt->closeCursor(); + + return true; + } } |