From 85a95f1973e776f60709102be5f903133e182773 Mon Sep 17 00:00:00 2001 From: fipwmaqzufheoxq92ebc <29818044+fipwmaqzufheoxq92ebc@users.noreply.github.com> Date: Sun, 6 Sep 2020 10:00:49 +0200 Subject: [PATCH] Apikeys (#986) * Add QR-Code for API-Url/Key * Show only API-Keys for current user * Allow only admin users to create custom API-Keys * Use a managed package of qrcode-generator instead of a copy of the JS file * Reuse existing localization string (API key) * Center QR-Code in popups Co-authored-by: Bernd Bestel --- controllers/GenericEntityApiController.php | 11 +++++++++++ controllers/OpenApiController.php | 7 ++++++- grocy.openapi.json | 6 ++++++ package.json | 1 + public/js/extensions.js | 16 ++++++++++++++++ public/viewjs/calendar.js | 3 ++- public/viewjs/manageapikeys.js | 9 +++++++++ views/calendar.blade.php | 1 + views/manageapikeys.blade.php | 10 ++++++++++ yarn.lock | 5 +++++ 10 files changed, 67 insertions(+), 2 deletions(-) diff --git a/controllers/GenericEntityApiController.php b/controllers/GenericEntityApiController.php index 47cf2ace..8db371ed 100644 --- a/controllers/GenericEntityApiController.php +++ b/controllers/GenericEntityApiController.php @@ -13,6 +13,9 @@ class GenericEntityApiController extends BaseApiController if ($this->IsValidEntity($args['entity'])) { + if($this->IsEntityWithEditRequiresAdmin($args['entity'])) + User::checkPermission($request, User::PERMISSION_ADMIN); + $requestBody = $request->getParsedBody(); try @@ -47,6 +50,8 @@ class GenericEntityApiController extends BaseApiController if ($this->IsValidEntity($args['entity'])) { + if($this->IsEntityWithEditRequiresAdmin($args['entity'])) + User::checkPermission($request, User::PERMISSION_ADMIN); $row = $this->getDatabase()->{$args['entity']} ($args['objectId']); $row->delete(); @@ -65,6 +70,8 @@ class GenericEntityApiController extends BaseApiController if ($this->IsValidEntity($args['entity'])) { + if($this->IsEntityWithEditRequiresAdmin($args['entity'])) + User::checkPermission($request, User::PERMISSION_ADMIN); $requestBody = $request->getParsedBody(); try @@ -211,6 +218,10 @@ class GenericEntityApiController extends BaseApiController { parent::__construct($container); } + private function IsEntityWithEditRequiresAdmin($entity) + { + return !in_array($entity, $this->getOpenApiSpec()->components->internalSchemas->EntityEditRequiresAdmin->enum); + } private function IsEntityWithPreventedListing($entity) { diff --git a/controllers/OpenApiController.php b/controllers/OpenApiController.php index 6b9e6177..813af27f 100644 --- a/controllers/OpenApiController.php +++ b/controllers/OpenApiController.php @@ -2,12 +2,17 @@ namespace Grocy\Controllers; +use Grocy\Controllers\Users\User; + class OpenApiController extends BaseApiController { public function ApiKeysList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { + $apiKeys = $this->getDatabase()->api_keys(); + if(!User::hasPermissions(User::PERMISSION_ADMIN)) + $apiKeys = $apiKeys->where('user_id', GROCY_USER_ID); return $this->renderPage($response, 'manageapikeys', [ - 'apiKeys' => $this->getDatabase()->api_keys(), + 'apiKeys' =>$apiKeys, 'users' => $this->getDatabase()->users() ]); } diff --git a/grocy.openapi.json b/grocy.openapi.json index b8d587b1..b569a82a 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -3483,6 +3483,12 @@ "meal_plan" ] }, + "EntityEditRequiresAdmin": { + "type": "string", + "enum": [ + "api_keys" + ] + }, "StockTransactionType": { "type": "string", "enum": [ diff --git a/package.json b/package.json index 1ac78d3a..064a39ba 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "jquery-serializejson": "^2.9.0", "moment": "^2.27.0", "nosleep.js": "^0.11.0", + "qrcode-generator": "^1.4.4", "sprintf-js": "^1.1.2", "startbootstrap-sb-admin": "4.0.0", "summernote": "^0.8.18", diff --git a/public/js/extensions.js b/public/js/extensions.js index 53baefe2..4c42d4fd 100644 --- a/public/js/extensions.js +++ b/public/js/extensions.js @@ -175,3 +175,19 @@ function animateCSS(selector, animationName, callback, speed = "faster") function RandomString() { return Math.random().toString(36).substring(2, 100) + Math.random().toString(36).substring(2, 100); } +function getQRCodeForContent(url) +{ + var qr = qrcode(0, 'L'); + qr.addData(url); + qr.make(); + return qr.createImgTag(10, 5); +} +function getQRCodeForAPIKey(apikey_type, apikey_key) +{ + var content = U('/api') + '|' + apikey_key; + if(apikey_type === 'special-purpose-calendar-ical') + { + content = U('/api/calendar/ical?secret=' + apikey_key); + } + return getQRCodeForContent(content); +} diff --git a/public/viewjs/calendar.js b/public/viewjs/calendar.js index 9c8461b6..e4507295 100644 --- a/public/viewjs/calendar.js +++ b/public/viewjs/calendar.js @@ -32,7 +32,8 @@ $("#ical-button").on("click", function(e) { bootbox.alert({ title: __t('Share/Integrate calendar (iCal)'), - message: __t('Use the following (public) URL to share or integrate the calendar in iCal format') + '', + message: __t('Use the following (public) URL to share or integrate the calendar in iCal format') + '

' + + getQRCodeForContent(result.url) + "

", closeButton: false }); }, diff --git a/public/viewjs/manageapikeys.js b/public/viewjs/manageapikeys.js index 59a97756..07e03c46 100644 --- a/public/viewjs/manageapikeys.js +++ b/public/viewjs/manageapikeys.js @@ -61,3 +61,12 @@ $(document).on('click', '.apikey-delete-button', function(e) } }); }); +$('.apikey-show-qr-button').on('click', function() +{ + var qrcodeHtml = getQRCodeForAPIKey($(this).data('apikey-key'), $(this).data('apikey-type')); + bootbox.alert({ + title: __t('API key'), + message: "

" + qrcodeHtml + "

", + closeButton: false + }); +}) diff --git a/views/calendar.blade.php b/views/calendar.blade.php index 43ee25c0..7e236223 100644 --- a/views/calendar.blade.php +++ b/views/calendar.blade.php @@ -7,6 +7,7 @@ @push('pageScripts') @if(!empty($__t('fullcalendar_locale') && $__t('fullcalendar_locale') != 'x'))@endif + @endpush @push('pageStyles') diff --git a/views/manageapikeys.blade.php b/views/manageapikeys.blade.php index 3dfab1d1..9ad804bd 100644 --- a/views/manageapikeys.blade.php +++ b/views/manageapikeys.blade.php @@ -4,6 +4,10 @@ @section('activeNav', '') @section('viewJsName', 'manageapikeys') +@push('pageScripts') + +@endpush + @push('pageStyles') @@ -63,6 +67,12 @@ data-apikey-apikey="{{ $apiKey->api_key }}"> + + + {{ $apiKey->api_key }} diff --git a/yarn.lock b/yarn.lock index 5107b91c..d2dff438 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2920,6 +2920,11 @@ pupa@^2.0.1: dependencies: escape-goat "^2.0.0" +qrcode-generator@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/qrcode-generator/-/qrcode-generator-1.4.4.tgz#63f771224854759329a99048806a53ed278740e7" + integrity sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw== + qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"