diff --git a/api_keys.php b/api_keys.php
index d57fa51b..0c1e0835 100644
--- a/api_keys.php
+++ b/api_keys.php
@@ -32,36 +32,43 @@ $success_message = "";
$id = (int) Request::get('id');
// do the delete and then just show a success-message and the apikeys list again
-if ($action == 'delete') {
- if ($id > 0) {
- $chk = (AREA == 'admin' && $userinfo['customers_see_all'] == '1') ? true : false;
- if (AREA == 'customer') {
- $chk_stmt = Database::prepare("
+if ($action == 'delete' && $id > 0) {
+ \Froxlor\UI\HTML::askYesNo('apikey_reallydelete', $filename, array(
+ 'id' => $id,
+ 'page' => $page,
+ 'action' => 'deletesure'
+ ), '', [
+ 'section' => 'index',
+ 'page' => $page
+ ]);
+} elseif ($action == 'deletesure' && $id > 0) {
+ $chk = (AREA == 'admin' && $userinfo['customers_see_all'] == '1') ? true : false;
+ if (AREA == 'customer') {
+ $chk_stmt = Database::prepare("
SELECT c.customerid FROM `" . TABLE_PANEL_CUSTOMERS . "` c
LEFT JOIN `" . TABLE_API_KEYS . "` ak ON ak.customerid = c.customerid
WHERE ak.`id` = :id AND c.`customerid` = :cid
");
- $chk = Database::pexecute_first($chk_stmt, array(
- 'id' => $id,
- 'cid' => $userinfo['customerid']
- ));
- } elseif (AREA == 'admin' && $userinfo['customers_see_all'] == '0') {
- $chk_stmt = Database::prepare("
+ $chk = Database::pexecute_first($chk_stmt, array(
+ 'id' => $id,
+ 'cid' => $userinfo['customerid']
+ ));
+ } elseif (AREA == 'admin' && $userinfo['customers_see_all'] == '0') {
+ $chk_stmt = Database::prepare("
SELECT a.adminid FROM `" . TABLE_PANEL_ADMINS . "` a
LEFT JOIN `" . TABLE_API_KEYS . "` ak ON ak.adminid = a.adminid
WHERE ak.`id` = :id AND a.`adminid` = :aid
");
- $chk = Database::pexecute_first($chk_stmt, array(
- 'id' => $id,
- 'aid' => $userinfo['adminid']
- ));
- }
- if ($chk !== false) {
- Database::pexecute($del_stmt, array(
- 'id' => $id
- ));
- $success_message = sprintf($lng['apikeys']['apikey_removed'], $id);
- }
+ $chk = Database::pexecute_first($chk_stmt, array(
+ 'id' => $id,
+ 'aid' => $userinfo['adminid']
+ ));
+ }
+ if ($chk !== false) {
+ Database::pexecute($del_stmt, array(
+ 'id' => $id
+ ));
+ $success_message = sprintf($lng['apikeys']['apikey_removed'], $id);
}
} elseif ($action == 'add') {
$ins_stmt = Database::prepare("
@@ -83,47 +90,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..9af17e2d 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!');
}
@@ -117,11 +121,13 @@ class Ajax
public function errorResponse($message, int $response_code = 500)
{
+ header("Content-Type: application/json");
return \Froxlor\Api\Response::jsonErrorResponse($message, $response_code);
}
public function jsonResponse($value, int $response_code = 200)
{
+ header("Content-Type: application/json");
return \Froxlor\Api\Response::jsonResponse($value, $response_code);
}
@@ -193,7 +199,7 @@ class Ajax
]);
}
- return $items;
+ return $this->jsonResponse($items);
} else {
return $this->errorResponse('No Newsfeeds available at the moment.');
}
@@ -206,8 +212,8 @@ class Ajax
try {
$json_result = \Froxlor\Api\Commands\Froxlor::getLocal($this->userinfo)->checkUpdate();
$result = json_decode($json_result, true)['data'];
- echo UI::twig()->render($this->theme . '/misc/version_top.html.twig', $result);
- exit;
+ $result = UI::twig()->render($this->theme . '/misc/version_top.html.twig', $result);
+ return $this->jsonResponse($result);
} catch (Exception $e) {
// don't display anything if just not allowed due to permissions
if ($e->getCode() != 403) {
@@ -236,8 +242,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 +254,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..1ebae861 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/Domain.php b/lib/Froxlor/UI/Callbacks/Domain.php
index 42c9e4c9..713b255b 100644
--- a/lib/Froxlor/UI/Callbacks/Domain.php
+++ b/lib/Froxlor/UI/Callbacks/Domain.php
@@ -61,9 +61,24 @@ class Domain
return UI::getLng('domains.aliasdomain') . ' ' . $attributes['fields']['aliasdomain'];
}
- public static function domainExternalLink(array $attributes)
+ public static function domainExternalLinkInfo(array $attributes)
{
- return '' . $attributes['data'] . '';
+ $result = '' . $attributes['data'] . '';
+ // check for statistics if parentdomainid==0 to show stats-link for customers
+ if ((int) UI::getCurrentUser()['adminsession'] == 0 && $attributes['fields']['parentdomainid'] == 0) {
+ $statsapp = 'webalizer';
+ if (Settings::Get('system.awstats_enabled') == '1') {
+ $statsapp = 'awstats';
+ }
+ $result .= ' ';
+ }
+ if ($attributes['fields']['registration_date'] != '') {
+ $result .= '
' . UI::getLng('domains.registration_date') . ': ' . $attributes['fields']['registration_date'] . '';
+ }
+ if ($attributes['fields']['termination_date'] != '') {
+ $result .= '
' . UI::getLng('domains.termination_date_overview') . ': ' . $attributes['fields']['termination_date'] . '';
+ }
+ return $result;
}
public static function canEdit(array $attributes): bool
diff --git a/lib/Froxlor/UI/Callbacks/Style.php b/lib/Froxlor/UI/Callbacks/Style.php
index d34b521e..6ff1ea9a 100644
--- a/lib/Froxlor/UI/Callbacks/Style.php
+++ b/lib/Froxlor/UI/Callbacks/Style.php
@@ -46,6 +46,21 @@ class Style
return $isValid ? '' : 'bg-danger';
}
+ public static function resultDomainTerminatedOrDeactivated(array $attributes): string
+ {
+ $termination_date = str_replace("0000-00-00", "", $attributes['fields']['termination_date'] ?? '');
+ $termination_css = '';
+ if (!empty($termination_date)) {
+ $cdate = strtotime($termination_date . " 23:59:59");
+ $today = time();
+ $termination_css = 'bg-warning';
+ if ($cdate < $today) {
+ $termination_css = 'bg-danger';
+ }
+ }
+ return $attributes['fields']['deactivated'] ? 'bg-info' : $termination_css;
+ }
+
public static function diskspaceWarning(array $attributes): string
{
return self::getWarningStyle('diskspace', $attributes['fields'], (int)Settings::Get('system.report_webmax'));
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/Froxlor/UI/HTML.php b/lib/Froxlor/UI/HTML.php
index 6d9cf22a..5f6af921 100644
--- a/lib/Froxlor/UI/HTML.php
+++ b/lib/Froxlor/UI/HTML.php
@@ -169,12 +169,13 @@ class HTML
* Values which will be given to $yesfile. Format: array(variable1=>value1, variable2=>value2, variable3=>value3)
* @param string $replacer
* value of a possible existing string-replacer in the question
+ * @param array $back_link
*
* @author Froxlor team
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,6 @@ $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';
+$lng['question']['apikey_reallydelete'] = 'Do you really want to delete this api-key?';
diff --git a/lng/german.lng.php b/lng/german.lng.php
index f9720c73..722ddc1e 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,5 @@ $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';
+$lng['question']['plan_reallydelete'] = 'Wollen Sie den Api-Key wirklich löschen?';
diff --git a/templates/Froxlor/form/yesnoquestion.html.twig b/templates/Froxlor/form/yesnoquestion.html.twig
index 22036cec..73dfec30 100644
--- a/templates/Froxlor/form/yesnoquestion.html.twig
+++ b/templates/Froxlor/form/yesnoquestion.html.twig
@@ -23,7 +23,11 @@
{% endfor %}
- {{ lng('panel.no') }}
+ {% if back_link is defined and back_link is iterable %}
+ {{ lng('panel.no') }}
+ {% else %}
+ {{ lng('panel.no') }}
+ {% endif %}