mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 01:32:38 +00:00
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 <bernd@berrnd.de>
This commit is contained in:
parent
40f379b761
commit
85a95f1973
@ -13,6 +13,9 @@ class GenericEntityApiController extends BaseApiController
|
|||||||
|
|
||||||
if ($this->IsValidEntity($args['entity']))
|
if ($this->IsValidEntity($args['entity']))
|
||||||
{
|
{
|
||||||
|
if($this->IsEntityWithEditRequiresAdmin($args['entity']))
|
||||||
|
User::checkPermission($request, User::PERMISSION_ADMIN);
|
||||||
|
|
||||||
$requestBody = $request->getParsedBody();
|
$requestBody = $request->getParsedBody();
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -47,6 +50,8 @@ class GenericEntityApiController extends BaseApiController
|
|||||||
|
|
||||||
if ($this->IsValidEntity($args['entity']))
|
if ($this->IsValidEntity($args['entity']))
|
||||||
{
|
{
|
||||||
|
if($this->IsEntityWithEditRequiresAdmin($args['entity']))
|
||||||
|
User::checkPermission($request, User::PERMISSION_ADMIN);
|
||||||
$row = $this->getDatabase()->{$args['entity']}
|
$row = $this->getDatabase()->{$args['entity']}
|
||||||
($args['objectId']);
|
($args['objectId']);
|
||||||
$row->delete();
|
$row->delete();
|
||||||
@ -65,6 +70,8 @@ class GenericEntityApiController extends BaseApiController
|
|||||||
|
|
||||||
if ($this->IsValidEntity($args['entity']))
|
if ($this->IsValidEntity($args['entity']))
|
||||||
{
|
{
|
||||||
|
if($this->IsEntityWithEditRequiresAdmin($args['entity']))
|
||||||
|
User::checkPermission($request, User::PERMISSION_ADMIN);
|
||||||
$requestBody = $request->getParsedBody();
|
$requestBody = $request->getParsedBody();
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -211,6 +218,10 @@ class GenericEntityApiController extends BaseApiController
|
|||||||
{
|
{
|
||||||
parent::__construct($container);
|
parent::__construct($container);
|
||||||
}
|
}
|
||||||
|
private function IsEntityWithEditRequiresAdmin($entity)
|
||||||
|
{
|
||||||
|
return !in_array($entity, $this->getOpenApiSpec()->components->internalSchemas->EntityEditRequiresAdmin->enum);
|
||||||
|
}
|
||||||
|
|
||||||
private function IsEntityWithPreventedListing($entity)
|
private function IsEntityWithPreventedListing($entity)
|
||||||
{
|
{
|
||||||
|
@ -2,12 +2,17 @@
|
|||||||
|
|
||||||
namespace Grocy\Controllers;
|
namespace Grocy\Controllers;
|
||||||
|
|
||||||
|
use Grocy\Controllers\Users\User;
|
||||||
|
|
||||||
class OpenApiController extends BaseApiController
|
class OpenApiController extends BaseApiController
|
||||||
{
|
{
|
||||||
public function ApiKeysList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
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', [
|
return $this->renderPage($response, 'manageapikeys', [
|
||||||
'apiKeys' => $this->getDatabase()->api_keys(),
|
'apiKeys' =>$apiKeys,
|
||||||
'users' => $this->getDatabase()->users()
|
'users' => $this->getDatabase()->users()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -3483,6 +3483,12 @@
|
|||||||
"meal_plan"
|
"meal_plan"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"EntityEditRequiresAdmin": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"api_keys"
|
||||||
|
]
|
||||||
|
},
|
||||||
"StockTransactionType": {
|
"StockTransactionType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
"jquery-serializejson": "^2.9.0",
|
"jquery-serializejson": "^2.9.0",
|
||||||
"moment": "^2.27.0",
|
"moment": "^2.27.0",
|
||||||
"nosleep.js": "^0.11.0",
|
"nosleep.js": "^0.11.0",
|
||||||
|
"qrcode-generator": "^1.4.4",
|
||||||
"sprintf-js": "^1.1.2",
|
"sprintf-js": "^1.1.2",
|
||||||
"startbootstrap-sb-admin": "4.0.0",
|
"startbootstrap-sb-admin": "4.0.0",
|
||||||
"summernote": "^0.8.18",
|
"summernote": "^0.8.18",
|
||||||
|
@ -175,3 +175,19 @@ function animateCSS(selector, animationName, callback, speed = "faster")
|
|||||||
function RandomString() {
|
function RandomString() {
|
||||||
return Math.random().toString(36).substring(2, 100) + Math.random().toString(36).substring(2, 100);
|
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);
|
||||||
|
}
|
||||||
|
@ -32,7 +32,8 @@ $("#ical-button").on("click", function(e)
|
|||||||
{
|
{
|
||||||
bootbox.alert({
|
bootbox.alert({
|
||||||
title: __t('Share/Integrate calendar (iCal)'),
|
title: __t('Share/Integrate calendar (iCal)'),
|
||||||
message: __t('Use the following (public) URL to share or integrate the calendar in iCal format') + '<input type="text" class="form-control form-control-sm mt-2 easy-link-copy-textbox" value="' + result.url + '">',
|
message: __t('Use the following (public) URL to share or integrate the calendar in iCal format') + '<input type="text" class="form-control form-control-sm mt-2 easy-link-copy-textbox" value="' + result.url + '"><p class="text-center mt-4">'
|
||||||
|
+ getQRCodeForContent(result.url) + "</p>",
|
||||||
closeButton: false
|
closeButton: false
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -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: "<p class='text-center'>" + qrcodeHtml + "</p>",
|
||||||
|
closeButton: false
|
||||||
|
});
|
||||||
|
})
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
@push('pageScripts')
|
@push('pageScripts')
|
||||||
<script src="{{ $U('/node_modules/fullcalendar/dist/fullcalendar.min.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/node_modules/fullcalendar/dist/fullcalendar.min.js?v=', true) }}{{ $version }}"></script>
|
||||||
@if(!empty($__t('fullcalendar_locale') && $__t('fullcalendar_locale') != 'x'))<script src="{{ $U('/node_modules', true) }}/fullcalendar/dist/locale/{{ $__t('fullcalendar_locale') }}.js?v={{ $version }}"></script>@endif
|
@if(!empty($__t('fullcalendar_locale') && $__t('fullcalendar_locale') != 'x'))<script src="{{ $U('/node_modules', true) }}/fullcalendar/dist/locale/{{ $__t('fullcalendar_locale') }}.js?v={{ $version }}"></script>@endif
|
||||||
|
<script src="{{ $U('/node_modules/qrcode-generator/qrcode.js?v=', true) }}{{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
@section('activeNav', '')
|
@section('activeNav', '')
|
||||||
@section('viewJsName', 'manageapikeys')
|
@section('viewJsName', 'manageapikeys')
|
||||||
|
|
||||||
|
@push('pageScripts')
|
||||||
|
<script src="{{ $U('/node_modules/qrcode-generator/qrcode.js?v=', true) }}{{ $version }}"></script>
|
||||||
|
@endpush
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
@ -63,6 +67,12 @@
|
|||||||
data-apikey-apikey="{{ $apiKey->api_key }}">
|
data-apikey-apikey="{{ $apiKey->api_key }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="btn btn-info btn-sm apikey-show-qr-button"
|
||||||
|
href="#"
|
||||||
|
data-apikey-key="{{ $apiKey->api_key }}"
|
||||||
|
data-apikey-type="{{ $apiKey->key_type }}">
|
||||||
|
<i class="fas fa-qrcode"></i>
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $apiKey->api_key }}
|
{{ $apiKey->api_key }}
|
||||||
|
@ -2920,6 +2920,11 @@ pupa@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
escape-goat "^2.0.0"
|
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:
|
qs@~6.5.2:
|
||||||
version "6.5.2"
|
version "6.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user