diff --git a/app/src/Apikey/ApikeyApi.php b/app/src/Apikey/ApikeyApi.php new file mode 100644 index 000000000..7fca3abe9 --- /dev/null +++ b/app/src/Apikey/ApikeyApi.php @@ -0,0 +1,76 @@ +baseApiUrl . '/v2.1/token'; + + $tokens = (array) json_decode( + $this->apiGet($token_uri, $queryParams) + ); + $meta = array_pop($tokens); + + $collectionData = array(); + foreach ($tokens['tokens'] as $item) { + $talk = new ApiKeyEntity($item); + + $collectionData['tokens'][] = $talk; + } + + $collectionData['pagination'] = $meta; + + return $collectionData; + } + + /** + * Get a specified API-key associated with the current user + * + * @return ApikeyEntity + */ + public function getById($id, $queryParams = ['verbose' => 'yes']) + { + $tokens_uri = $this->baseApiUrl . '/v2.1/token/' . urlencode($id); + + $tokens = (array) json_decode( + $this->apiGet($tokens_uri, $queryParams) + ); + + + if (! isset($tokens['tokens'][0])) { + throw new \UnexpectedValueException('No tokens available'); + } + + return new ApikeyEntity($tokens['tokens'][0]); + } + + /** + * @param $tokenUri + * + * @throws \Exception + * @return bool + */ + public function deleteClient($tokenUri) + { + list ($status, $result, $headers) = $this->apiDelete($tokenUri); + + if ($status != 204) { + $decoded = json_decode($result); + if (is_array($decoded)) { + $result = current($decoded); + } + throw new \Exception($result); + } + + return true; + + } +} diff --git a/app/src/Apikey/ApikeyController.php b/app/src/Apikey/ApikeyController.php new file mode 100644 index 000000000..d1d79b2de --- /dev/null +++ b/app/src/Apikey/ApikeyController.php @@ -0,0 +1,100 @@ +get('/apikey', array($this, 'index'))->name('apikey-show'); + $app->get('/apikey/:apikey/delete', array($this, 'deleteApiKey'))->via('GET', 'POST')->name('apikey-delete'); + } + + public function index() + { + if (! isset($_SESSION['user'])) { + $thisUrl = $this->application->urlFor('apikey-show'); + $this->application->redirect( + $this->application->urlFor('not-allowed') . '?redirect=' . $thisUrl + ); + } + + $tokenApi = $this->getApikeyApi(); + $tokens = $tokenApi->getCollection([]); + + $this->render('Apikey/index.html.twig', ['keys' => $tokens['tokens']]); + } + + public function deleteApiKey($apikey) + { + if (!isset($_SESSION['user'])) { + $thisUrl = $this->application->urlFor('apikey-delete', ['apikey' => $apikey]); + $this->application->redirect( + $this->application->urlFor('not-allowed') . '?redirect=' . $thisUrl + ); + } + + $apikeyApi = $this->getApikeyApi(); + try { + $apikey = $apikeyApi->getById($apikey); + } catch (Exception $e) { + $this->application->notFound(); + return; + } + + // default values + $data = []; + $data['apikey_id'] = $apikey->getId(); + + $factory = $this->application->formFactory; + $form = $factory->create(new ApikeyDeleteFormType(), $data); + + $request = $this->application->request(); + + if ($request->isPost()) { + $form->submit($request->post($form->getName())); + + if ($form->isValid()) { + try { + $apikeyApi->deleteClient($apikey->getApiUri()); + + $this->application->flash('message', sprintf( + 'The API-Key %s has been permanently removed', + $apikey->getId() + )); + $this->application->redirect( + $this->application->urlFor('apikey-show') + ); + return; + } catch (\RuntimeException $e) { + $form->adderror( + new FormError('An error occurred while removing this API-Key: ' . $e->getmessage()) + ); + } + } + } + + $this->render( + 'Apikey/delete.html.twig', + [ + 'apikey' => $apikey, + 'form' => $form->createView(), + 'backUri' => $this->application->urlFor('apikey-show'), + ] + ); + } + + /** + * @return ClientApi + */ + private function getApikeyApi() + { + return new ApikeyApi($this->cfg, $this->accessToken); + } +} diff --git a/app/src/Apikey/ApikeyDeleteFormType.php b/app/src/Apikey/ApikeyDeleteFormType.php new file mode 100644 index 000000000..3028159e9 --- /dev/null +++ b/app/src/Apikey/ApikeyDeleteFormType.php @@ -0,0 +1,44 @@ +add( + 'apikey_id', + 'hidden', + [] + ) + ; + } +} diff --git a/app/src/Apikey/ApikeyEntity.php b/app/src/Apikey/ApikeyEntity.php new file mode 100644 index 000000000..944729557 --- /dev/null +++ b/app/src/Apikey/ApikeyEntity.php @@ -0,0 +1,35 @@ +data->token_uri, strrpos($this->data->token_uri, '/') + 1); + } + + public function getApplicationName() + { + return $this->data->application; + } + + public function getLastUsedDateTime() + { + return new \DateTimeImmutable($this->data->last_used_date); + } + + public function getCreationDateTime() + { + return new \DateTimeImmutable($this->data->created_date); + } + + + public function getApiUri() + { + return $this->data->token_uri; + } +} diff --git a/app/templates/Apikey/_common/deleteform.html.twig b/app/templates/Apikey/_common/deleteform.html.twig new file mode 100644 index 000000000..79a04e2ea --- /dev/null +++ b/app/templates/Apikey/_common/deleteform.html.twig @@ -0,0 +1,29 @@ +{% block form %} + {% if user %} + {{ form_start(form, {'attr' : {'id' : 'apikey'} }) }} + {{ form_errors(form) }} +
+
+

+ You are about to permanently remove the API-key for + {{ apikey.getApplicationName }}. +

+ You will need to log in with {{ apikey.getApplicationName }} to use the application again! +

+ Are you sure you want to do delete this key? +

+
+
+
+
+ {{ form_row(form.apikey_id) }} + + Cancel +
+
+ {{ form_end(form) }} + {% else %} +

Login required

+

In order to delete a key, please log in.

+ {% endif %} +{% endblock %} diff --git a/app/templates/Apikey/delete.html.twig b/app/templates/Apikey/delete.html.twig new file mode 100755 index 000000000..58cc6fb95 --- /dev/null +++ b/app/templates/Apikey/delete.html.twig @@ -0,0 +1,25 @@ +{% extends '/layout.html.twig' %} + +{% block title %}Delete API-key - Joind.in{% endblock %} + +{% form_theme form _self %} +{% use '/Apikey/_common/deleteform.html.twig' %} + +{% block body %} + + + + + {{ block('form') }} +{% endblock %} \ No newline at end of file diff --git a/app/templates/Apikey/index.html.twig b/app/templates/Apikey/index.html.twig new file mode 100755 index 000000000..df9064b9e --- /dev/null +++ b/app/templates/Apikey/index.html.twig @@ -0,0 +1,46 @@ +{% extends '/layout.html.twig' %} + +{% block title %}ApiKeys - Joind.in{% endblock %} + +{% block body %} + + + +
+

My API-keys

+ + + + + + + {% if keys %} + + {% for key in keys %} + + + + {% endfor %} + + {% endif %} +
Applicationlast used 
+ {{ key.getApplicationName }} + + {{ key.getLastUsedDateTime | date('d.m.Y H:i:s') }} + + + Delete Api-Key + +
+
+ +{% endblock %} + + +{% block topAside %} +{% endblock %} + +{% block extraAside %} +{% endblock %} diff --git a/app/templates/User/profile.html.twig b/app/templates/User/profile.html.twig index 8c3570250..7d496c152 100644 --- a/app/templates/User/profile.html.twig +++ b/app/templates/User/profile.html.twig @@ -20,7 +20,12 @@ {% if thisUser.canEdit %}

- Edit + Edit + + — + + API-Keys +

{% endif %} diff --git a/composer.json b/composer.json index 6477bff47..0eaa5bcc7 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "Search": ["app/src/", "tests/"], "Talk": ["app/src/", "tests/"], "User": ["app/src/", "tests/"], - "Client": ["app/src/", "tests/"] + "Client": ["app/src/", "tests/"], + "Apikey": ["app/src/", "tests/"] } }, "config": { diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php index 58e05ec37..ceab4a00f 100644 --- a/vendor/composer/autoload_namespaces.php +++ b/vendor/composer/autoload_namespaces.php @@ -29,4 +29,5 @@ 'Event' => array($baseDir . '/app/src', $baseDir . '/tests'), 'Client' => array($baseDir . '/app/src', $baseDir . '/tests'), 'Application' => array($baseDir . '/app/src', $baseDir . '/tests'), + 'Apikey' => array($baseDir . '/app/src', $baseDir . '/tests'), ); diff --git a/web/index.php b/web/index.php index dcb1ad302..474a73e88 100644 --- a/web/index.php +++ b/web/index.php @@ -102,6 +102,7 @@ new User\UserController($app); new Talk\TalkController($app); new Client\ClientController($app); +new Apikey\ApikeyController($app); // execute application $app->run();