diff --git a/api_keys.php b/api_keys.php
index d57fa51b..55c187e8 100644
--- a/api_keys.php
+++ b/api_keys.php
@@ -83,47 +83,6 @@ if ($action == 'delete') {
'cid' => $cid
));
$success_message = $lng['apikeys']['apikey_added'];
-} elseif ($action == 'jqEditApiKey') {
- $keyid = isset($_POST['id']) ? (int) $_POST['id'] : 0;
- $allowed_from = isset($_POST['allowed_from']) ? $_POST['allowed_from'] : "";
- $valid_until = isset($_POST['valid_until']) ? (int) $_POST['valid_until'] : -1;
-
- // validate allowed_from
- if (!empty($allowed_from)) {
- $ip_list = array_map('trim', explode(",", $allowed_from));
- $_check_list = $ip_list;
- foreach ($_check_list as $idx => $ip) {
- if (\Froxlor\Validate\Validate::validate_ip2($ip, true, 'invalidip', true, true) == false) {
- unset($ip_list[$idx]);
- }
- }
- $ip_list = array_map('inet_ntop', array_map('inet_pton', $ip_list));
- $allowed_from = implode(",", array_unique($ip_list));
- }
-
- if ($valid_until <= 0 || !is_numeric($valid_until)) {
- $valid_until = -1;
- }
-
- $upd_stmt = Database::prepare("
- UPDATE `" . TABLE_API_KEYS . "` SET
- `valid_until` = :vu, `allowed_from` = :af
- WHERE `id` = :keyid AND `adminid` = :aid AND `customerid` = :cid
- ");
- if (AREA == 'admin') {
- $cid = 0;
- } elseif (AREA == 'customer') {
- $cid = $userinfo['customerid'];
- }
- Database::pexecute($upd_stmt, array(
- 'keyid' => $keyid,
- 'af' => $allowed_from,
- 'vu' => $valid_until,
- 'aid' => $userinfo['adminid'],
- 'cid' => $cid
- ));
- echo json_encode(true);
- exit();
}
$log->logAction(\Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed api::api_keys");
diff --git a/install/lib/class.FroxlorInstall.php b/install/lib/class.FroxlorInstall.php
index 89d8d8bc..8469718d 100644
--- a/install/lib/class.FroxlorInstall.php
+++ b/install/lib/class.FroxlorInstall.php
@@ -444,7 +444,7 @@ class FroxlorInstall
`vhostcontainer` = '1',
`vhostcontainer_servername_statement` = '1'
");
- $nvh = $this->_data['webserver'] == 'apache2' ? '1' : '0';
+ $nvh = $this->_data['webserver'] == 'apache2' ? '1' : '0';
$stmt->execute(array(
'nvh' => $nvh,
'serverip' => $this->_data['serverip'],
@@ -1193,6 +1193,9 @@ class FroxlorInstall
// check for json extension
$this->_requirementCheckFor($content, $_die, 'json', false, 'phpjson');
+ // check for gmp extension
+ $this->_requirementCheckFor($content, $_die, 'gmp', false, 'phpgmp');
+
// check for bcmath extension
$this->_requirementCheckFor($content, $_die, 'bcmath', true, 'phpbcmath', 'bcmathdescription');
diff --git a/install/lng/english.lng.php b/install/lng/english.lng.php
index 73ef9d4e..031c6ff8 100644
--- a/install/lng/english.lng.php
+++ b/install/lng/english.lng.php
@@ -36,6 +36,7 @@ $lng['requirements']['phpcurl'] = 'PHP curl-extension...';
$lng['requirements']['phpmbstring'] = 'PHP mbstring-extension...';
$lng['requirements']['phpzip'] = 'PHP zip-extension...';
$lng['requirements']['phpjson'] = 'PHP json-extension...';
+$lng['requirements']['phpgmp'] = 'PHP gmp-extension...';
$lng['requirements']['bcmathdescription'] = 'Traffic-calculation related functions will not work correctly!';
$lng['requirements']['zipdescription'] = 'The auto-update feature requires the zip extension.';
$lng['requirements']['openbasedir'] = 'open_basedir...';
diff --git a/install/lng/german.lng.php b/install/lng/german.lng.php
index a3ac7c6a..0a1226ed 100644
--- a/install/lng/german.lng.php
+++ b/install/lng/german.lng.php
@@ -36,6 +36,7 @@ $lng['requirements']['phpcurl'] = 'PHP curl-Erweiterung...';
$lng['requirements']['phpmbstring'] = 'PHP mbstring-Erweiterung...';
$lng['requirements']['phpzip'] = 'PHP zip-Erweiterung...';
$lng['requirements']['phpjson'] = 'PHP json-Erweiterung...';
+$lng['requirements']['phpgmp'] = 'PHP gmp-Erweiterung...';
$lng['requirements']['bcmathdescription'] = 'Traffic-Berechnungs bezogene Funktionen stehen nicht vollständig zur Verfügung!';
$lng['requirements']['zipdescription'] = 'Die Auto-Update Funktion benötigt die zip Erweiterung.';
$lng['requirements']['openbasedir'] = 'open_basedir genutzt wird...';
diff --git a/lib/Froxlor/Ajax/Ajax.php b/lib/Froxlor/Ajax/Ajax.php
index de9123a5..e5c8ee95 100644
--- a/lib/Froxlor/Ajax/Ajax.php
+++ b/lib/Froxlor/Ajax/Ajax.php
@@ -3,7 +3,9 @@
namespace Froxlor\Ajax;
use Exception;
+use Froxlor\Database\Database;
use Froxlor\Http\HttpClient;
+use Froxlor\Validate\Validate;
use Froxlor\Settings;
use Froxlor\UI\Listing;
use Froxlor\UI\Panel\UI;
@@ -52,7 +54,7 @@ class Ajax
global $lng;
// query the whole table
- $result_stmt = \Froxlor\Database\Database::query("SELECT * FROM `" . TABLE_PANEL_LANGUAGE . "`");
+ $result_stmt = Database::query("SELECT * FROM `" . TABLE_PANEL_LANGUAGE . "`");
$langs = array();
// presort languages
@@ -110,6 +112,8 @@ class Ajax
return $this->searchGlobal();
case 'tablelisting':
return $this->updateTablelisting();
+ case 'editapikey':
+ return $this->editApiKey();
default:
return $this->errorResponse('Action not found!');
}
@@ -236,8 +240,7 @@ class Ajax
$result = array_merge($result_settings, $result_entities);
- header("Content-type: application/json");
- echo json_encode($result);
+ return $this->jsonResponse($result);
}
private function updateTablelisting()
@@ -249,6 +252,61 @@ class Ajax
Listing::storeColumnListingForUser([Request::get('listing') => $columns]);
- return json_encode($columns);
+ return $this->jsonResponse($columns);
+ }
+
+ private function editApiKey()
+ {
+ $keyid = isset($_POST['id']) ? (int) $_POST['id'] : 0;
+ $allowed_from = isset($_POST['allowed_from']) ? $_POST['allowed_from'] : "";
+ $valid_until = isset($_POST['valid_until']) ? (int) $_POST['valid_until'] : -1;
+
+ // validate allowed_from
+ if (!empty($allowed_from)) {
+ $ip_list = array_map('trim', explode(",", $allowed_from));
+ $_check_list = $ip_list;
+ foreach ($_check_list as $idx => $ip) {
+ if (Validate::validate_ip2($ip, true, 'invalidip', true, true, true) == false) {
+ unset($ip_list[$idx]);
+ continue;
+ }
+ // check for cidr
+ if (strpos($ip, '/') !== false) {
+ $ipparts = explode("/", $ip);
+ // shorten IP
+ $ip = inet_ntop(inet_pton($ipparts[0]));
+ // re-add cidr
+ $ip .= '/' . $ipparts[1];
+ } else {
+ // shorten IP
+ $ip = inet_ntop(inet_pton($ip));
+ }
+ $ip_list[$idx] = $ip;
+ }
+ $allowed_from = implode(",", array_unique($ip_list));
+ }
+
+ if ($valid_until <= 0 || !is_numeric($valid_until)) {
+ $valid_until = -1;
+ }
+
+ $upd_stmt = Database::prepare("
+ UPDATE `" . TABLE_API_KEYS . "` SET
+ `valid_until` = :vu, `allowed_from` = :af
+ WHERE `id` = :keyid AND `adminid` = :aid AND `customerid` = :cid
+ ");
+ if ((int) $this->userinfo['adminsession'] == 1) {
+ $cid = 0;
+ } else {
+ $cid = $this->userinfo['customerid'];
+ }
+ Database::pexecute($upd_stmt, array(
+ 'keyid' => $keyid,
+ 'af' => $allowed_from,
+ 'vu' => $valid_until,
+ 'aid' => $this->userinfo['adminid'],
+ 'cid' => $cid
+ ));
+ return $this->jsonResponse(['allowed_from' => $allowed_from, 'valid_until' => $valid_until]);
}
}
diff --git a/lib/Froxlor/Api/Response.php b/lib/Froxlor/Api/Response.php
index a88cb795..c03d4b29 100644
--- a/lib/Froxlor/Api/Response.php
+++ b/lib/Froxlor/Api/Response.php
@@ -1,4 +1,5 @@
$data], $response_code);
- }
+ public static function jsonDataResponse($data = null, int $response_code = 200)
+ {
+ return self::jsonResponse(['data' => $data], $response_code);
+ }
- public static function jsonErrorResponse($message = null, int $response_code = 400)
- {
- return self::jsonResponse(['message' => $message], $response_code);
- }
+ public static function jsonErrorResponse($message = null, int $response_code = 400)
+ {
+ return self::jsonResponse(['message' => $message], $response_code);
+ }
}
diff --git a/lib/Froxlor/UI/Callbacks/Text.php b/lib/Froxlor/UI/Callbacks/Text.php
index 12e6ead0..6f1c3156 100644
--- a/lib/Froxlor/UI/Callbacks/Text.php
+++ b/lib/Froxlor/UI/Callbacks/Text.php
@@ -79,6 +79,7 @@ class Text
'editid' => $attributes['fields']['id']
]);
return [
+ 'entry' => $attributes['fields']['id'],
'id' => 'akModal' . $attributes['fields']['id'],
'title' => 'API-key ' . ($attributes['fields']['loginname'] ?? $attributes['fields']['adminname']),
'body' => $body
diff --git a/lib/formfields/formfield.api_key.php b/lib/formfields/formfield.api_key.php
index 2bff23a4..3e96fe33 100644
--- a/lib/formfields/formfield.api_key.php
+++ b/lib/formfields/formfield.api_key.php
@@ -40,15 +40,15 @@ return [
'value' => $result['secret']
],
'allowed_from' => [
- 'label' => UI::getLng('apikeys.allowed_from'),
+ 'label' => ['title' => UI::getLng('apikeys.allowed_from'), 'description' => UI::getLng('apikeys.allowed_from_help')],
'type' => 'text',
'value' => $result['allowed_from'],
],
'valid_until' => [
- 'label' => UI::getLng('apikeys.valid_until'),
+ 'label' => ['title' => UI::getLng('apikeys.valid_until'), 'description' => UI::getLng('apikeys.valid_until_help')],
+ /** @TODO datetime-picker */
'type' => 'text',
- 'value' => $result['valid_until'],
- 'format_callback' => [Text::class, 'timestampUntil'],
+ 'value' => $result['valid_until'] < 0 ? "" : $result['valid_until']
]
]
]
diff --git a/lng/english.lng.php b/lng/english.lng.php
index 43fb1ca1..629438da 100644
--- a/lng/english.lng.php
+++ b/lng/english.lng.php
@@ -2041,7 +2041,7 @@ $lng['apikeys']['apikey_removed'] = 'The api key with the id #%s has been remove
$lng['apikeys']['apikey_added'] = 'A new api key has been generated successfully';
$lng['apikeys']['clicktoview'] = 'Click to view';
$lng['apikeys']['allowed_from'] = 'Allowed from';
-$lng['apikeys']['allowed_from_help'] = 'Comma separated list of ip addresses. Default empty.
Specifying a subnet e.g. 192.168.1.1/24 is currently not supported.';
+$lng['apikeys']['allowed_from_help'] = 'Comma separated list of ip addresses / networks.
Default is empty (allow from all).';
$lng['apikeys']['valid_until'] = 'Valid until';
$lng['apikeys']['valid_until_help'] = 'Date until valid, format YYYY-MM-DD';
$lng['serversettings']['enable_api']['title'] = 'Enable external API usage';
@@ -2167,5 +2167,5 @@ $lng['panel']['settingsmodebasic'] = 'Basic';
$lng['panel']['settingsmodeadvanced'] = 'Advanced';
$lng['panel']['settingsmodetoggle'] = 'Click to toggle mode';
$lng['panel']['modalclose'] = 'Close';
-$lng['panel']['managetablecolumnsmodal']['title'] = 'Manage Table columns';
-$lng['panel']['managetablecolumnsmodal']['description'] = 'Here you can individualise the table columns for yourself.';
+$lng['panel']['managetablecolumnsmodal']['title'] = 'Manage table columns';
+$lng['panel']['managetablecolumnsmodal']['description'] = 'Here you can customize the visible columns';
diff --git a/lng/german.lng.php b/lng/german.lng.php
index f9720c73..51299826 100644
--- a/lng/german.lng.php
+++ b/lng/german.lng.php
@@ -1683,7 +1683,7 @@ $lng['apikeys']['no_api_keys'] = 'Keine API Keys gefunden';
$lng['apikeys']['key_add'] = 'API Key hinzufügen';
$lng['apikeys']['apikey_removed'] = 'Der API Key mit der ID #%s wurde erfolgreich gelöscht.';
$lng['apikeys']['allowed_from'] = 'Erlaube Zugriff von';
-$lng['apikeys']['allowed_from_help'] = 'Komma getrennte Liste von IPs. Standard ist leer.
Angabe von Subnetzen z.B. 192.168.1.1/24 wird derzeit nicht unterstützt.';
+$lng['apikeys']['allowed_from_help'] = 'Komma getrennte Liste von IPs oder Netzen.
Standard ist leer (von überall erlaubt).';
$lng['apikeys']['valid_until'] = 'Gültig bis';
$lng['apikeys']['valid_until_help'] = 'Datum Gültigkeitsende, Format JJJJ-MM-TT';
$lng['serversettings']['enable_api']['title'] = 'Aktiviere externe API Nutzung';
@@ -1806,4 +1806,4 @@ $lng['panel']['settingsmodeadvanced'] = 'Erweitert';
$lng['panel']['settingsmodetoggle'] = 'Modus umschalten';
$lng['panel']['modalclose'] = 'Schließen';
$lng['panel']['managetablecolumnsmodal']['title'] = 'Tabellenspalten verwalten';
-$lng['panel']['managetablecolumnsmodal']['description'] = 'Hier kannst du die Tabellenspalten für dich selbst individualisieren.';
+$lng['panel']['managetablecolumnsmodal']['description'] = 'Hier können die angezeigten Tabellenspalten angepasst werden';
diff --git a/templates/Froxlor/src/js/components/apikeys.js b/templates/Froxlor/src/js/components/apikeys.js
new file mode 100644
index 00000000..41db9028
--- /dev/null
+++ b/templates/Froxlor/src/js/components/apikeys.js
@@ -0,0 +1,57 @@
+$(function () {
+
+ var timer, delay = 500;
+ $('div[data-action="apikeys"] #allowed_from').on('keyup change', function () {
+ var _this = $(this);
+ clearTimeout(timer);
+ timer = setTimeout(function () {
+ var akid = $('div[data-action="apikeys"]').data('entry');
+ $.ajax({
+ url: "lib/ajax.php?action=editapikey",
+ type: "POST",
+ dataType: "json",
+ data: { id: akid, allowed_from: _this.val(), valid_until: $('div[data-action="apikeys"] #valid_until').val() },
+ success: function (data) {
+ if (data.message) {
+ _this.removeClass('is-valid');
+ _this.addClass('is-invalid');
+ } else {
+ _this.removeClass('is-invalid');
+ _this.addClass('is-valid');
+ _this.val(data.allowed_from);
+ }
+ },
+ error: function (request, status, error) {
+ console.log(request, status, error)
+ }
+ });
+ }, delay);
+ });
+
+ $('div[data-action="apikeys"] #valid_until').on('keyup change', function () {
+ var _this = $(this);
+ clearTimeout(timer);
+ timer = setTimeout(function () {
+ var akid = $('div[data-action="apikeys"]').data('entry');
+ $.ajax({
+ url: "lib/ajax.php?action=editapikey",
+ type: "POST",
+ dataType: "json",
+ data: { id: akid, valid_until: _this.val(), allowed_from: $('div[data-action="apikeys"] #allowed_from').val() },
+ success: function (data) {
+ if (data.message) {
+ _this.removeClass('is-valid');
+ _this.addClass('is-invalid');
+ } else {
+ _this.removeClass('is-invalid');
+ _this.addClass('is-valid');
+ _this.val(data.valid_until);
+ }
+ },
+ error: function (request, status, error) {
+ console.log(request, status, error)
+ }
+ });
+ }, delay);
+ });
+});
diff --git a/templates/Froxlor/src/js/components/configfiles.js b/templates/Froxlor/src/js/components/configfiles.js
index 6ea59352..2a7f97b4 100644
--- a/templates/Froxlor/src/js/components/configfiles.js
+++ b/templates/Froxlor/src/js/components/configfiles.js
@@ -1,8 +1,8 @@
-$(document).ready(function () {
+$(function() {
/*
* config files - select all recommended
*/
- $('#selectRecommendedConfig').click(function () {
+ $('#selectRecommendedConfig').on('click', function () {
$('input[data-recommended]').each(function () {
if ($(this).data('recommended') == 1) {
$(this).prop('checked', true);
diff --git a/templates/Froxlor/src/js/components/customer.js b/templates/Froxlor/src/js/components/customer.js
index f04e1e0f..eefe02af 100644
--- a/templates/Froxlor/src/js/components/customer.js
+++ b/templates/Froxlor/src/js/components/customer.js
@@ -1,4 +1,4 @@
-$(document).ready(function () {
+$(function() {
// Make inputs with enabled unlimited checked disabled
$("input[name$='_ul']").each(function () {
@@ -9,7 +9,7 @@ $(document).ready(function () {
});
});
// change state when unlimited checkboxes are clicked
- $("input[name$='_ul']").change(function () {
+ $("input[name$='_ul']").on('change', function () {
var fieldname = $(this).attr("name").substring(0, $(this).attr("name").length - 3);
$("input[name='" + fieldname + "']").prop({
readonly: $(this).is(":checked"),
@@ -21,7 +21,7 @@ $(document).ready(function () {
});
// set values from hosting plan when adding/editing a customer according to the plan's values
- $('#use_plan').change(function () {
+ $('#use_plan').on('change', function () {
var pid = $(this).val();
if (pid > 0) {
$.ajax({
diff --git a/templates/Froxlor/src/js/components/domains.js b/templates/Froxlor/src/js/components/domains.js
index cd083411..67817d54 100644
--- a/templates/Froxlor/src/js/components/domains.js
+++ b/templates/Froxlor/src/js/components/domains.js
@@ -1,7 +1,7 @@
-$(document).ready(function () {
+$(function() {
// disable unusable php-configuration by customer settings
- $('#customerid').change(function () {
+ $('#customerid').on('change', function () {
var cid = $(this).val();
$.ajax({
url: "admin_domains.php?page=domains&action=jqGetCustomerPHPConfigs",
@@ -31,7 +31,7 @@ $(document).ready(function () {
// show warning if speciallogfile option is toggled
if ($('input[name=speciallogverified]')) {
- $('input[name=speciallogfile]').click(function () {
+ $('input[name=speciallogfile]').on('click', function () {
$('#speciallogfilenote').remove();
$('#speciallogfile').removeClass('is-invalid');
$('#speciallogverified').val(0);
@@ -64,7 +64,7 @@ $(document).ready(function () {
$('#section_d').hide();
}
- $('#email_only').click(function () {
+ $('#email_only').on('click', function () {
if ($(this).is(':checked')) {
// hide unnecessary sections
$('#section_b').hide();
diff --git a/templates/Froxlor/src/js/components/ipsandports.js b/templates/Froxlor/src/js/components/ipsandports.js
index 50c40a7a..c42b6da4 100644
--- a/templates/Froxlor/src/js/components/ipsandports.js
+++ b/templates/Froxlor/src/js/components/ipsandports.js
@@ -1,7 +1,7 @@
-$(document).ready(function () {
+$(function() {
// check for internal ip and output a notice if private-range ip is given
- $('#ip').change(function () {
+ $('#ip').on('change', function () {
var ipval = $(this).val();
if (ipval.length > 0) {
$('#ipnote').remove();
diff --git a/templates/Froxlor/src/js/components/newsfeed.js b/templates/Froxlor/src/js/components/newsfeed.js
index 8e4fb8c2..2776eeb3 100644
--- a/templates/Froxlor/src/js/components/newsfeed.js
+++ b/templates/Froxlor/src/js/components/newsfeed.js
@@ -1,4 +1,4 @@
-$(document).ready(function () {
+$(function() {
/*
* newsfeed
*/
diff --git a/templates/Froxlor/src/js/components/search.js b/templates/Froxlor/src/js/components/search.js
index 40dd2c06..92115aab 100644
--- a/templates/Froxlor/src/js/components/search.js
+++ b/templates/Froxlor/src/js/components/search.js
@@ -1,7 +1,7 @@
-$(document).ready(function () {
+$(function() {
let search = $('#search')
- search.submit(function (e) {
+ search.on('submit', function (e) {
e.preventDefault();
});
diff --git a/templates/Froxlor/src/js/components/updatecheck.js b/templates/Froxlor/src/js/components/updatecheck.js
index e5da6103..9a7cae69 100644
--- a/templates/Froxlor/src/js/components/updatecheck.js
+++ b/templates/Froxlor/src/js/components/updatecheck.js
@@ -1,4 +1,4 @@
-$(document).ready(function () {
+$(function() {
/*
* updatecheck
*/
diff --git a/templates/Froxlor/src/js/main.js b/templates/Froxlor/src/js/main.js
index 613523ed..a548ef2b 100644
--- a/templates/Froxlor/src/js/main.js
+++ b/templates/Froxlor/src/js/main.js
@@ -6,7 +6,7 @@ import 'chart.js/dist/chart';
// load jquery
global.$ = require('jquery');
-$(document).ready(function () {
+$(function() {
window.$theme = 'Froxlor';
});
@@ -19,3 +19,4 @@ require('./components/tablecolumns')
require('./components/ipsandports')
require('./components/domains')
require('./components/configfiles')
+require('./components/apikeys')
diff --git a/templates/Froxlor/table/macros.html.twig b/templates/Froxlor/table/macros.html.twig
index 3944e548..0908277a 100644
--- a/templates/Froxlor/table/macros.html.twig
+++ b/templates/Froxlor/table/macros.html.twig
@@ -53,7 +53,7 @@
{% endif %}
{% if data.modal is defined and data.modal is iterable %}
-