Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63bbcd4e00 | ||
|
|
49d67d7c27 | ||
|
|
7cc4c9fedb | ||
|
|
afd110a6ed | ||
|
|
7cdf6c8d64 | ||
|
|
60621da243 | ||
|
|
96ccdda304 | ||
|
|
4073984fd7 | ||
|
|
ea31c8a64d | ||
|
|
832ee07e0e | ||
|
|
b542b140c6 | ||
|
|
ac89fc7120 | ||
|
|
150858485d | ||
|
|
e7810e2066 | ||
|
|
4879446567 | ||
|
|
43eff78088 | ||
|
|
55a2ae3801 | ||
|
|
a3b0332d13 | ||
|
|
4b1846883d | ||
|
|
778fd3ba65 | ||
|
|
00456a35e5 | ||
|
|
5958f0516b | ||
|
|
166ffedf04 | ||
|
|
36dfee1263 | ||
|
|
ec0026ecfd | ||
|
|
a721bb3f21 | ||
|
|
83de3dd719 |
@@ -248,7 +248,7 @@ return [
|
|||||||
'settinggroup' => 'system',
|
'settinggroup' => 'system',
|
||||||
'varname' => 'le_domain_dnscheck_resolver',
|
'varname' => 'le_domain_dnscheck_resolver',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'string_regexp' => '/^(([0-9]+ [a-z0-9\-\._]+, ?)*[0-9]+ [a-z0-9\-\._]+)?$/i',
|
'string_type' => 'validate_ip',
|
||||||
'string_emptyallowed' => true,
|
'string_emptyallowed' => true,
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'save_method' => 'storeSettingField'
|
'save_method' => 'storeSettingField'
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ if ($userinfo['change_serversettings'] == '1') {
|
|||||||
|
|
||||||
if (!empty($distribution)) {
|
if (!empty($distribution)) {
|
||||||
if (!file_exists($config_dir . '/' . $distribution . ".xml")) {
|
if (!file_exists($config_dir . '/' . $distribution . ".xml")) {
|
||||||
Response::dynamicError("Unknown distribution");
|
// unknown distribution -> redirect to select a valid distribution for config-templates
|
||||||
|
Settings::Set('system.distribution', '');
|
||||||
|
Response::redirectTo('admin_configfiles.php', ['reselect' => 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update setting if different
|
// update setting if different
|
||||||
|
|||||||
@@ -115,8 +115,8 @@ if ($page == 'overview') {
|
|||||||
$userinfo['traffic_bytes_used'] = $userinfo['traffic_used'] * 1024;
|
$userinfo['traffic_bytes_used'] = $userinfo['traffic_used'] * 1024;
|
||||||
|
|
||||||
if (Settings::Get('system.mail_quota_enabled')) {
|
if (Settings::Get('system.mail_quota_enabled')) {
|
||||||
$userinfo['email_quota_bytes'] = ($userinfo['email_quota'] > -1) ? $userinfo['email_quota'] * 1024 : -1;
|
$userinfo['email_quota_bytes'] = ($userinfo['email_quota'] > -1) ? $userinfo['email_quota'] * 1024 * 1024 : -1;
|
||||||
$userinfo['email_quota_bytes_used'] = $userinfo['email_quota_used'] * 1024;
|
$userinfo['email_quota_bytes_used'] = $userinfo['email_quota_used'] * 1024 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($usages) {
|
if ($usages) {
|
||||||
|
|||||||
17
index.php
17
index.php
@@ -74,27 +74,26 @@ if ($action == '2fa_entercode') {
|
|||||||
$code = isset($_POST['2fa_code']) ? $_POST['2fa_code'] : null;
|
$code = isset($_POST['2fa_code']) ? $_POST['2fa_code'] : null;
|
||||||
// verify entered code
|
// verify entered code
|
||||||
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
|
||||||
$result = ($_SESSION['secret_2fa'] == 'email' ? true : $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3));
|
|
||||||
// get user-data
|
// get user-data
|
||||||
$table = $_SESSION['uidtable_2fa'];
|
$table = $_SESSION['uidtable_2fa'];
|
||||||
$field = $_SESSION['uidfield_2fa'];
|
$field = $_SESSION['uidfield_2fa'];
|
||||||
$uid = $_SESSION['uid_2fa'];
|
$uid = $_SESSION['uid_2fa'];
|
||||||
$isadmin = $_SESSION['unfo_2fa'];
|
$isadmin = $_SESSION['unfo_2fa'];
|
||||||
|
if ($_SESSION['secret_2fa'] == 'email') {
|
||||||
|
// verify code set to user's data_2fa field
|
||||||
|
$sel_stmt = Database::prepare("SELECT `data_2fa` FROM " . $table . " WHERE `" . $field . "` = :uid");
|
||||||
|
$userinfo_code = Database::pexecute_first($sel_stmt, ['uid' => $uid]);
|
||||||
|
$result = $tfa->verifyCode($userinfo_code['data_2fa'], $code);
|
||||||
|
} else {
|
||||||
|
$result = $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3);
|
||||||
|
}
|
||||||
// either the code is valid when using authenticator-app, or we will select userdata by id and entered code
|
// either the code is valid when using authenticator-app, or we will select userdata by id and entered code
|
||||||
// which is temporarily stored for the customer when using email-2fa
|
// which is temporarily stored for the customer when using email-2fa
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$sel_param = [
|
$sel_param = [
|
||||||
'uid' => $uid
|
'uid' => $uid
|
||||||
];
|
];
|
||||||
if ($_SESSION['secret_2fa'] == 'email') {
|
|
||||||
// verify code by selecting user by id and the temp. stored code,
|
|
||||||
// so only if it's the correct code, we get the user-data
|
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid AND `data_2fa` = :code");
|
|
||||||
$sel_param['code'] = $code;
|
|
||||||
} else {
|
|
||||||
// Authenticator-verification has already happened at this point, so just get the user-data
|
|
||||||
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid");
|
$sel_stmt = Database::prepare("SELECT * FROM " . $table . " WHERE `" . $field . "` = :uid");
|
||||||
}
|
|
||||||
$userinfo = Database::pexecute_first($sel_stmt, $sel_param);
|
$userinfo = Database::pexecute_first($sel_stmt, $sel_param);
|
||||||
// whoops, no (valid) user? Start again
|
// whoops, no (valid) user? Start again
|
||||||
if (empty($userinfo)) {
|
if (empty($userinfo)) {
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ CREATE TABLE `panel_admins` (
|
|||||||
`api_allowed` tinyint(1) NOT NULL default '1',
|
`api_allowed` tinyint(1) NOT NULL default '1',
|
||||||
PRIMARY KEY (`adminid`),
|
PRIMARY KEY (`adminid`),
|
||||||
UNIQUE KEY `loginname` (`loginname`)
|
UNIQUE KEY `loginname` (`loginname`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_customers`;
|
DROP TABLE IF EXISTS `panel_customers`;
|
||||||
@@ -299,7 +299,7 @@ CREATE TABLE `panel_domains` (
|
|||||||
KEY `customerid` (`customerid`),
|
KEY `customerid` (`customerid`),
|
||||||
KEY `parentdomain` (`parentdomainid`),
|
KEY `parentdomain` (`parentdomainid`),
|
||||||
KEY `domain` (`domain`)
|
KEY `domain` (`domain`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_ipsandports`;
|
DROP TABLE IF EXISTS `panel_ipsandports`;
|
||||||
@@ -678,7 +678,7 @@ opcache.validate_timestamps'),
|
|||||||
('system', 'distribution', ''),
|
('system', 'distribution', ''),
|
||||||
('system', 'update_channel', 'stable'),
|
('system', 'update_channel', 'stable'),
|
||||||
('system', 'updatecheck_data', ''),
|
('system', 'updatecheck_data', ''),
|
||||||
('system', 'update_notify_last', '2.1.1'),
|
('system', 'update_notify_last', ''),
|
||||||
('system', 'traffictool', 'goaccess'),
|
('system', 'traffictool', 'goaccess'),
|
||||||
('system', 'req_limit_per_interval', 60),
|
('system', 'req_limit_per_interval', 60),
|
||||||
('system', 'req_limit_interval', 60),
|
('system', 'req_limit_interval', 60),
|
||||||
@@ -686,7 +686,7 @@ opcache.validate_timestamps'),
|
|||||||
('api', 'customer_default', '1'),
|
('api', 'customer_default', '1'),
|
||||||
('2fa', 'enabled', '1'),
|
('2fa', 'enabled', '1'),
|
||||||
('panel', 'decimal_places', '4'),
|
('panel', 'decimal_places', '4'),
|
||||||
('panel', 'adminmail', 'admin@SERVERNAME'),
|
('panel', 'adminmail', 'ADMIN_MAIL'),
|
||||||
('panel', 'phpmyadmin_url', ''),
|
('panel', 'phpmyadmin_url', ''),
|
||||||
('panel', 'webmail_url', ''),
|
('panel', 'webmail_url', ''),
|
||||||
('panel', 'webftp_url', ''),
|
('panel', 'webftp_url', ''),
|
||||||
@@ -726,8 +726,8 @@ opcache.validate_timestamps'),
|
|||||||
('panel', 'logo_overridecustom', '0'),
|
('panel', 'logo_overridecustom', '0'),
|
||||||
('panel', 'settings_mode', '0'),
|
('panel', 'settings_mode', '0'),
|
||||||
('panel', 'menu_collapsed', '1'),
|
('panel', 'menu_collapsed', '1'),
|
||||||
('panel', 'version', '2.1.1'),
|
('panel', 'version', '2.1.4'),
|
||||||
('panel', 'db_version', '202312050');
|
('panel', 'db_version', '202312120');
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `panel_tasks`;
|
DROP TABLE IF EXISTS `panel_tasks`;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ if (!defined('_CRON_UPDATE')) {
|
|||||||
|
|
||||||
if (Froxlor::isFroxlorVersion('2.0.24')) {
|
if (Froxlor::isFroxlorVersion('2.0.24')) {
|
||||||
Update::showUpdateStep("Cleaning domains table");
|
Update::showUpdateStep("Cleaning domains table");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ROW_FORMAT=DYNAMIC;");
|
||||||
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` DROP COLUMN `ismainbutsubto`;");
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` DROP COLUMN `ismainbutsubto`;");
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
@@ -213,3 +214,68 @@ if (Froxlor::isFroxlorVersion('2.1.0')) {
|
|||||||
Update::showUpdateStep("Updating from 2.1.0 to 2.1.1", false);
|
Update::showUpdateStep("Updating from 2.1.0 to 2.1.1", false);
|
||||||
Froxlor::updateToVersion('2.1.1');
|
Froxlor::updateToVersion('2.1.1');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202312050')) {
|
||||||
|
Update::showUpdateStep("Cleaning up old files");
|
||||||
|
$to_clean = array(
|
||||||
|
"lib/configfiles/centos7.xml",
|
||||||
|
"lib/configfiles/centos8.xml",
|
||||||
|
"lib/configfiles/stretch.xml",
|
||||||
|
"lib/configfiles/xenial.xml",
|
||||||
|
"lib/configfiles/buster.xml",
|
||||||
|
"lib/configfiles/bionic.xml",
|
||||||
|
);
|
||||||
|
$disabled = explode(',', ini_get('disable_functions'));
|
||||||
|
$exec_allowed = !in_array('exec', $disabled);
|
||||||
|
$del_list = "";
|
||||||
|
foreach ($to_clean as $filedir) {
|
||||||
|
$complete_filedir = Froxlor::getInstallDir() . $filedir;
|
||||||
|
if (file_exists($complete_filedir)) {
|
||||||
|
if ($exec_allowed) {
|
||||||
|
FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir));
|
||||||
|
} else {
|
||||||
|
$del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($exec_allowed) {
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
if (empty($del_list)) {
|
||||||
|
// none of the files existed
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
} else {
|
||||||
|
Update::lastStepStatus(
|
||||||
|
1,
|
||||||
|
'manual commands needed',
|
||||||
|
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Froxlor::updateToDbVersion('202312100');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isDatabaseVersion('202312100')) {
|
||||||
|
|
||||||
|
Update::showUpdateStep("Adjusting table row format of larger tables");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` ROW_FORMAT=DYNAMIC;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ROW_FORMAT=DYNAMIC;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Froxlor::updateToDbVersion('202312120');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.1')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.1 to 2.1.2", false);
|
||||||
|
Froxlor::updateToVersion('2.1.2');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.2')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.2 to 2.1.3", false);
|
||||||
|
Froxlor::updateToVersion('2.1.3');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Froxlor::isFroxlorVersion('2.1.3')) {
|
||||||
|
Update::showUpdateStep("Updating from 2.1.3 to 2.1.4", false);
|
||||||
|
Froxlor::updateToVersion('2.1.4');
|
||||||
|
}
|
||||||
|
|||||||
@@ -1053,7 +1053,7 @@ class Customers extends ApiCommand implements ResourceEntity
|
|||||||
$email = $this->getParam('email', true, $idna_convert->decode($result['email']));
|
$email = $this->getParam('email', true, $idna_convert->decode($result['email']));
|
||||||
$name = $this->getParam('name', true, $result['name']);
|
$name = $this->getParam('name', true, $result['name']);
|
||||||
$firstname = $this->getParam('firstname', true, $result['firstname']);
|
$firstname = $this->getParam('firstname', true, $result['firstname']);
|
||||||
$company_required = empty($result['company']) && ((!empty($name) && empty($firstname)) || (empty($name) && !empty($firstname)) || (empty($name) && empty($firstname)));
|
$company_required = (!empty($name) && empty($firstname)) || (empty($name) && !empty($firstname)) || (empty($name) && empty($firstname));
|
||||||
$company = $this->getParam('company', !$company_required, $result['company']);
|
$company = $this->getParam('company', !$company_required, $result['company']);
|
||||||
$street = $this->getParam('street', true, $result['street']);
|
$street = $this->getParam('street', true, $result['street']);
|
||||||
$zipcode = $this->getParam('zipcode', true, $result['zipcode']);
|
$zipcode = $this->getParam('zipcode', true, $result['zipcode']);
|
||||||
|
|||||||
@@ -259,14 +259,15 @@ class Froxlor extends ApiCommand
|
|||||||
* returns a random password based on froxlor settings for min-length, included characters, etc.
|
* returns a random password based on froxlor settings for min-length, included characters, etc.
|
||||||
*
|
*
|
||||||
* @param int $length
|
* @param int $length
|
||||||
* optional length of password, defaults to 10
|
* optional length of password, defaults to 0 (panel.password_min_length)
|
||||||
*
|
*
|
||||||
* @access admin, customer
|
* @access admin, customer
|
||||||
* @return string
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function generatePassword()
|
public function generatePassword(): string
|
||||||
{
|
{
|
||||||
$length = $this->getParam('length', true, 10);
|
$length = $this->getParam('length', true, 0);
|
||||||
return $this->response(Crypt::generatePassword($length));
|
return $this->response(Crypt::generatePassword($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -402,7 +402,7 @@ final class ConfigServices extends CliCommand
|
|||||||
case "file":
|
case "file":
|
||||||
if (array_key_exists('content', $action)) {
|
if (array_key_exists('content', $action)) {
|
||||||
$output->writeln('<comment>Creating file "' . $action['name'] . '"</>');
|
$output->writeln('<comment>Creating file "' . $action['name'] . '"</>');
|
||||||
file_put_contents($action['name'], trim(strtr($action['content'], $replace_arr)));
|
file_put_contents($action['name'], trim(strtr($action['content'], $replace_arr)) . PHP_EOL);
|
||||||
} elseif (array_key_exists('subcommands', $action)) {
|
} elseif (array_key_exists('subcommands', $action)) {
|
||||||
foreach ($action['subcommands'] as $fileaction) {
|
foreach ($action['subcommands'] as $fileaction) {
|
||||||
if (array_key_exists('execute', $fileaction) && $fileaction['execute'] == "pre") {
|
if (array_key_exists('execute', $fileaction) && $fileaction['execute'] == "pre") {
|
||||||
@@ -411,7 +411,7 @@ final class ConfigServices extends CliCommand
|
|||||||
exec(strtr($fileaction['content'], $replace_arr));
|
exec(strtr($fileaction['content'], $replace_arr));
|
||||||
} elseif ($fileaction['type'] == 'file') {
|
} elseif ($fileaction['type'] == 'file') {
|
||||||
$output->writeln('<comment>Creating file "' . $fileaction['name'] . '"</>');
|
$output->writeln('<comment>Creating file "' . $fileaction['name'] . '"</>');
|
||||||
file_put_contents($fileaction['name'], trim(strtr($fileaction['content'], $replace_arr)));
|
file_put_contents($fileaction['name'], trim(strtr($fileaction['content'], $replace_arr)) . PHP_EOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -514,6 +514,7 @@ final class ConfigServices extends CliCommand
|
|||||||
'<WEBSERVER_GROUP>' => Settings::Get('system.httpgroup'),
|
'<WEBSERVER_GROUP>' => Settings::Get('system.httpgroup'),
|
||||||
'<SSL_CERT_FILE>' => Settings::Get('system.ssl_cert_file'),
|
'<SSL_CERT_FILE>' => Settings::Get('system.ssl_cert_file'),
|
||||||
'<SSL_KEY_FILE>' => Settings::Get('system.ssl_key_file'),
|
'<SSL_KEY_FILE>' => Settings::Get('system.ssl_key_file'),
|
||||||
|
'<ADMIN_MAIL>' => Settings::Get('panel.adminmail'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ final class InstallCommand extends Command
|
|||||||
$ask_field = false;
|
$ask_field = false;
|
||||||
}
|
}
|
||||||
$fielddata['value'] = $this->formfielddata[$fieldname] ?? ($fielddata['value'] ?? null);
|
$fielddata['value'] = $this->formfielddata[$fieldname] ?? ($fielddata['value'] ?? null);
|
||||||
$fielddata['label'] = strip_tags(str_replace("<br>", " ", $fielddata['label']));
|
$fielddata['label'] = $this->cliTextFormat($fielddata['label'], " ");
|
||||||
if ($ask_field) {
|
if ($ask_field) {
|
||||||
if ($fielddata['type'] == 'password') {
|
if ($fielddata['type'] == 'password') {
|
||||||
$this->formfielddata[$fieldname] = $this->io->askHidden($fielddata['label'], function ($value) use ($fielddata) {
|
$this->formfielddata[$fieldname] = $this->io->askHidden($fielddata['label'], function ($value) use ($fielddata) {
|
||||||
@@ -267,15 +267,17 @@ final class InstallCommand extends Command
|
|||||||
case 4:
|
case 4:
|
||||||
$section = $inst->formfield['install']['sections']['step' . $step] ?? [];
|
$section = $inst->formfield['install']['sections']['step' . $step] ?? [];
|
||||||
$this->io->section($section['title']);
|
$this->io->section($section['title']);
|
||||||
$this->io->note($section['description']);
|
$this->io->note($this->cliTextFormat($section['description']));
|
||||||
$cmdfield = $section['fields']['system'];
|
$cmdfield = $section['fields']['system'];
|
||||||
$this->io->success([
|
$this->io->success([
|
||||||
$cmdfield['label'],
|
$cmdfield['label'],
|
||||||
$cmdfield['value']
|
$cmdfield['value']
|
||||||
]);
|
]);
|
||||||
|
if (!isset($decoded_input['manual_config']) || (bool)$decoded_input['manual_config'] === false) {
|
||||||
if (!empty($decoded_input) || $this->io->confirm('Execute command now?', false)) {
|
if (!empty($decoded_input) || $this->io->confirm('Execute command now?', false)) {
|
||||||
passthru($cmdfield['value']);
|
passthru($cmdfield['value']);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
@@ -305,7 +307,7 @@ final class InstallCommand extends Command
|
|||||||
$json_output = [];
|
$json_output = [];
|
||||||
foreach ($fields['install']['sections'] as $section => $section_fields) {
|
foreach ($fields['install']['sections'] as $section => $section_fields) {
|
||||||
foreach ($section_fields['fields'] as $name => $field) {
|
foreach ($section_fields['fields'] as $name => $field) {
|
||||||
if ($name == 'system' || $name == 'manual_config' || $name == 'target_servername') {
|
if ($name == 'system' || $name == 'target_servername') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($field['type'] == 'text' || $field['type'] == 'email') {
|
if ($field['type'] == 'text' || $field['type'] == 'email') {
|
||||||
@@ -318,7 +320,7 @@ final class InstallCommand extends Command
|
|||||||
$fieldval = '******';
|
$fieldval = '******';
|
||||||
} elseif ($field['type'] == 'select') {
|
} elseif ($field['type'] == 'select') {
|
||||||
$fieldval = implode("|", array_keys($field['select_var']));
|
$fieldval = implode("|", array_keys($field['select_var']));
|
||||||
} else if ($field['type'] == 'checkbox') {
|
} elseif ($field['type'] == 'checkbox') {
|
||||||
$fieldval = "1|0";
|
$fieldval = "1|0";
|
||||||
} else {
|
} else {
|
||||||
$fieldval = "?";
|
$fieldval = "?";
|
||||||
@@ -346,4 +348,10 @@ final class InstallCommand extends Command
|
|||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function cliTextFormat(string $text, string $nl_char = "\n"): string
|
||||||
|
{
|
||||||
|
$text = str_replace(['<br>', '<br/>', '<br />'], [$nl_char, $nl_char, $nl_char], $text);
|
||||||
|
return strip_tags($text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -263,6 +263,8 @@ final class MasterCron extends CliCommand
|
|||||||
if ($jobcount > 0) {
|
if ($jobcount > 0) {
|
||||||
if (Settings::Get('system.nssextrausers') == 1) {
|
if (Settings::Get('system.nssextrausers') == 1) {
|
||||||
Extrausers::generateFiles($this->cronLog);
|
Extrausers::generateFiles($this->cronLog);
|
||||||
|
// reload crond as shell users might use crontab and the user is only known to crond if reloaded
|
||||||
|
FileDir::safe_exec(escapeshellcmd(Settings::Get('system.crondreload')));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +277,8 @@ final class MasterCron extends CliCommand
|
|||||||
FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, [
|
FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, [
|
||||||
'>'
|
'>'
|
||||||
]);
|
]);
|
||||||
|
// reload crond as shell users might use crontab and the user is only known to crond if reloaded
|
||||||
|
FileDir::safe_exec(escapeshellcmd(Settings::Get('system.crondreload')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ class ConfigDisplay
|
|||||||
'<SQL_UNPRIVILEGED_PASSWORD>' => 'FROXLOR_MYSQL_PASSWORD',
|
'<SQL_UNPRIVILEGED_PASSWORD>' => 'FROXLOR_MYSQL_PASSWORD',
|
||||||
'<SQL_DB>' => $sql['db'],
|
'<SQL_DB>' => $sql['db'],
|
||||||
'<SQL_HOST>' => $sql['host'],
|
'<SQL_HOST>' => $sql['host'],
|
||||||
'<SQL_SOCKET>' => isset($sql['socket']) ? $sql['socket'] : null,
|
'<SQL_SOCKET>' => $sql['socket'] ?? null,
|
||||||
'<SERVERNAME>' => Settings::Get('system.hostname'),
|
'<SERVERNAME>' => Settings::Get('system.hostname'),
|
||||||
'<SERVERIP>' => Settings::Get('system.ipaddress'),
|
'<SERVERIP>' => Settings::Get('system.ipaddress'),
|
||||||
'<NAMESERVERS>' => Settings::Get('system.nameservers'),
|
'<NAMESERVERS>' => Settings::Get('system.nameservers'),
|
||||||
@@ -127,12 +127,15 @@ class ConfigDisplay
|
|||||||
'<VIRTUAL_GID_MAPS>' => Settings::Get('system.vmail_gid'),
|
'<VIRTUAL_GID_MAPS>' => Settings::Get('system.vmail_gid'),
|
||||||
'<SSLPROTOCOLS>' => (Settings::Get('system.use_ssl') == '1') ? 'imaps pop3s' : '',
|
'<SSLPROTOCOLS>' => (Settings::Get('system.use_ssl') == '1') ? 'imaps pop3s' : '',
|
||||||
'<CUSTOMER_TMP>' => FileDir::makeCorrectDir($customer_tmpdir),
|
'<CUSTOMER_TMP>' => FileDir::makeCorrectDir($customer_tmpdir),
|
||||||
'<BASE_PATH>' => FileDir::makeCorrectDir(Froxlor::getInstallDir()),
|
'<BASE_PATH>' => Froxlor::getInstallDir(),
|
||||||
'<BIND_CONFIG_PATH>' => FileDir::makeCorrectDir(Settings::Get('system.bindconf_directory')),
|
'<BIND_CONFIG_PATH>' => FileDir::makeCorrectDir(Settings::Get('system.bindconf_directory')),
|
||||||
'<WEBSERVER_RELOAD_CMD>' => Settings::Get('system.apachereload_command'),
|
'<WEBSERVER_RELOAD_CMD>' => Settings::Get('system.apachereload_command'),
|
||||||
'<CUSTOMER_LOGS>' => FileDir::makeCorrectDir(Settings::Get('system.logfiles_directory')),
|
'<CUSTOMER_LOGS>' => FileDir::makeCorrectDir(Settings::Get('system.logfiles_directory')),
|
||||||
'<FPM_IPCDIR>' => FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir')),
|
'<FPM_IPCDIR>' => FileDir::makeCorrectDir(Settings::Get('phpfpm.fastcgi_ipcdir')),
|
||||||
'<WEBSERVER_GROUP>' => Settings::Get('system.httpgroup')
|
'<WEBSERVER_GROUP>' => Settings::Get('system.httpgroup'),
|
||||||
|
'<SSL_CERT_FILE>' => Settings::Get('system.ssl_cert_file'),
|
||||||
|
'<SSL_KEY_FILE>' => Settings::Get('system.ssl_key_file'),
|
||||||
|
'<ADMIN_MAIL>' => Settings::Get('panel.adminmail'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$commands_pre = "";
|
$commands_pre = "";
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ abstract class DnsBase
|
|||||||
'zonefile' => '',
|
'zonefile' => '',
|
||||||
'froxlorhost' => '1'
|
'froxlorhost' => '1'
|
||||||
];
|
];
|
||||||
$domains['none'] = $hostname_arr;
|
$domains[0] = $hostname_arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($domains)) {
|
if (empty($domains)) {
|
||||||
|
|||||||
@@ -43,23 +43,29 @@ class DomainSSL
|
|||||||
* domain-array as reference so we can set the corresponding array-indices
|
* domain-array as reference so we can set the corresponding array-indices
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function setDomainSSLFilesArray(array &$domain = null)
|
public function setDomainSSLFilesArray(array &$domain = null)
|
||||||
{
|
{
|
||||||
// check if the domain itself has a certificate defined
|
// check if the domain itself has a certificate defined
|
||||||
$dom_certs_stmt = Database::prepare("
|
$dom_certs_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = :domid
|
SELECT s.*, d.domain
|
||||||
|
FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` s
|
||||||
|
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON d.id = s.domainid
|
||||||
|
WHERE s.`domainid` = :domid
|
||||||
");
|
");
|
||||||
$dom_certs = Database::pexecute_first($dom_certs_stmt, [
|
$dom_certs = Database::pexecute_first($dom_certs_stmt, [
|
||||||
'domid' => $domain['id']
|
'domid' => $domain['id']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$parent_certificate = false;
|
||||||
if (!is_array($dom_certs) || !isset($dom_certs['ssl_cert_file']) || $dom_certs['ssl_cert_file'] == '') {
|
if (!is_array($dom_certs) || !isset($dom_certs['ssl_cert_file']) || $dom_certs['ssl_cert_file'] == '') {
|
||||||
// maybe its parent?
|
// maybe its parent?
|
||||||
if (isset($domain['parentdomainid']) && $domain['parentdomainid'] != 0) {
|
if (isset($domain['parentdomainid']) && $domain['parentdomainid'] != 0) {
|
||||||
$dom_certs = Database::pexecute_first($dom_certs_stmt, [
|
$dom_certs = Database::pexecute_first($dom_certs_stmt, [
|
||||||
'domid' => $domain['parentdomainid']
|
'domid' => $domain['parentdomainid']
|
||||||
]);
|
]);
|
||||||
|
$parent_certificate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +79,8 @@ class DomainSSL
|
|||||||
}
|
}
|
||||||
// make correct files for the certificates
|
// make correct files for the certificates
|
||||||
$ssl_files = [
|
$ssl_files = [
|
||||||
'ssl_cert_file' => FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '.crt'),
|
'ssl_cert_file' => FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '.crt'),
|
||||||
'ssl_key_file' => FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '.key')
|
'ssl_key_file' => FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '.key')
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!$this->validateCertificate($dom_certs)) {
|
if (!$this->validateCertificate($dom_certs)) {
|
||||||
@@ -93,19 +99,19 @@ class DomainSSL
|
|||||||
$ssl_files['ssl_cert_chainfile'] = '';
|
$ssl_files['ssl_cert_chainfile'] = '';
|
||||||
// set them if they are != empty
|
// set them if they are != empty
|
||||||
if ($dom_certs['ssl_ca_file'] != '') {
|
if ($dom_certs['ssl_ca_file'] != '') {
|
||||||
$ssl_files['ssl_ca_file'] = FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '_CA.pem');
|
$ssl_files['ssl_ca_file'] = FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '_CA.pem');
|
||||||
}
|
}
|
||||||
if ($dom_certs['ssl_cert_chainfile'] != '') {
|
if ($dom_certs['ssl_cert_chainfile'] != '') {
|
||||||
if (Settings::Get('system.webserver') == 'nginx') {
|
if (Settings::Get('system.webserver') == 'nginx') {
|
||||||
// put ca.crt in my.crt, as nginx does not support a separate chain file.
|
// put ca.crt in my.crt, as nginx does not support a separate chain file.
|
||||||
$dom_certs['ssl_cert_file'] = trim($dom_certs['ssl_cert_file']) . "\n" . trim($dom_certs['ssl_cert_chainfile']) . "\n";
|
$dom_certs['ssl_cert_file'] = trim($dom_certs['ssl_cert_file']) . "\n" . trim($dom_certs['ssl_cert_chainfile']) . "\n";
|
||||||
} else {
|
} else {
|
||||||
$ssl_files['ssl_cert_chainfile'] = FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '_chain.pem');
|
$ssl_files['ssl_cert_chainfile'] = FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '_chain.pem');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// will only be generated to be used externally, froxlor does not need this
|
// will only be generated to be used externally, froxlor does not need this
|
||||||
if ($dom_certs['ssl_fullchain_file'] != '') {
|
if ($dom_certs['ssl_fullchain_file'] != '') {
|
||||||
$ssl_files['ssl_fullchain_file'] = FileDir::makeCorrectFile($sslcertpath . '/' . $domain['domain'] . '_fullchain.pem');
|
$ssl_files['ssl_fullchain_file'] = FileDir::makeCorrectFile($sslcertpath . '/' . ($parent_certificate ? $dom_certs['domain'] : $domain['domain']) . '_fullchain.pem');
|
||||||
}
|
}
|
||||||
// create them on the filesystem
|
// create them on the filesystem
|
||||||
foreach ($ssl_files as $type => $filename) {
|
foreach ($ssl_files as $type => $filename) {
|
||||||
@@ -131,7 +137,7 @@ class DomainSSL
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function validateCertificate($dom_certs = [])
|
private function validateCertificate($dom_certs = []): bool
|
||||||
{
|
{
|
||||||
return openssl_x509_check_private_key($dom_certs['ssl_cert_file'], $dom_certs['ssl_key_file']);
|
return openssl_x509_check_private_key($dom_certs['ssl_cert_file'], $dom_certs['ssl_key_file']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class TrafficCron extends FroxlorCron
|
|||||||
|
|
||||||
public static function run()
|
public static function run()
|
||||||
{
|
{
|
||||||
self::runFork([self::class, 'handle']);
|
self::runFork([self::class, 'handle'], [true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function handle()
|
public static function handle()
|
||||||
@@ -163,14 +163,14 @@ class TrafficCron extends FroxlorCron
|
|||||||
|
|
||||||
if (isset($domainlist[$row['customerid']]) && is_array($domainlist[$row['customerid']]) && count($domainlist[$row['customerid']]) != 0) {
|
if (isset($domainlist[$row['customerid']]) && is_array($domainlist[$row['customerid']]) && count($domainlist[$row['customerid']]) != 0) {
|
||||||
// Examining which caption to use for default webalizer stats...
|
// Examining which caption to use for default webalizer stats...
|
||||||
if ($row['standardsubdomain'] != '0') {
|
if ($row['standardsubdomain'] != '0' && isset($domainlist[$row['customerid']][$row['standardsubdomain']])) {
|
||||||
// ... of course we'd prefer to use the standardsubdomain ...
|
// ... of course we'd prefer to use the standardsubdomain ...
|
||||||
$caption = $domainlist[$row['customerid']][$row['standardsubdomain']];
|
$caption = $domainlist[$row['customerid']][$row['standardsubdomain']];
|
||||||
} else {
|
} else {
|
||||||
// ... but if there is no standardsubdomain, we have to use the loginname ...
|
// ... but if there is no standardsubdomain, we have to use the loginname ...
|
||||||
$caption = $row['loginname'];
|
$caption = $row['loginname'];
|
||||||
|
|
||||||
// ... which results in non-usable links to files in the stats, so lets have a look if we find a domain which is not speciallogfiledomain
|
// ... which results in non-usable links to files in the stats, so let's have a look if we find a domain which is not speciallogfiledomain
|
||||||
foreach ($domainlist[$row['customerid']] as $domainid => $domain) {
|
foreach ($domainlist[$row['customerid']] as $domainid => $domain) {
|
||||||
if (!isset($speciallogfile_domainlist[$row['customerid']]) || !isset($speciallogfile_domainlist[$row['customerid']][$domainid])) {
|
if (!isset($speciallogfile_domainlist[$row['customerid']]) || !isset($speciallogfile_domainlist[$row['customerid']][$domainid])) {
|
||||||
$caption = $domain;
|
$caption = $domain;
|
||||||
@@ -193,6 +193,8 @@ class TrafficCron extends FroxlorCron
|
|||||||
} else {
|
} else {
|
||||||
$httptraffic += floatval(self::callWebalizerGetTraffic($row['loginname'] . '-' . $domain, $row['documentroot'] . '/webalizer/' . $domain . '/', $domain, $domainlist[$row['customerid']]));
|
$httptraffic += floatval(self::callWebalizerGetTraffic($row['loginname'] . '-' . $domain, $row['documentroot'] . '/webalizer/' . $domain . '/', $domain, $domainlist[$row['customerid']]));
|
||||||
}
|
}
|
||||||
|
// kind of a keep-alive-call as this unsets the link which leads to a new connection to the database
|
||||||
|
Database::needRoot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,6 +212,8 @@ class TrafficCron extends FroxlorCron
|
|||||||
} else {
|
} else {
|
||||||
$httptraffic += floatval(self::callWebalizerGetTraffic($row['loginname'], $row['documentroot'] . '/webalizer/', $caption, $domainlist[$row['customerid']]));
|
$httptraffic += floatval(self::callWebalizerGetTraffic($row['loginname'], $row['documentroot'] . '/webalizer/', $caption, $domainlist[$row['customerid']]));
|
||||||
}
|
}
|
||||||
|
// kind of a keep-alive-call as this unsets the link which leads to a new connection to the database
|
||||||
|
Database::needRoot();
|
||||||
|
|
||||||
// make the stuff readable for the customer, #258
|
// make the stuff readable for the customer, #258
|
||||||
Statistics::makeChownWithNewStats($row);
|
Statistics::makeChownWithNewStats($row);
|
||||||
@@ -618,7 +622,7 @@ class TrafficCron extends FroxlorCron
|
|||||||
$format = Settings::Get('system.logfiles_type') == '2' ? 'VCOMBINED' : 'COMBINED';
|
$format = Settings::Get('system.logfiles_type') == '2' ? 'VCOMBINED' : 'COMBINED';
|
||||||
$monthyear = $monthyear_arr['month'] . '/' . $monthyear_arr['year'];
|
$monthyear = $monthyear_arr['month'] . '/' . $monthyear_arr['year'];
|
||||||
$return_value = false;
|
$return_value = false;
|
||||||
FileDir::safe_exec("grep '" . $monthyear . "' " . escapeshellarg($logfile) . " | goaccess " . $keep_params . " --db-path=" . escapeshellarg($outputdir) . " -o " . escapeshellarg($outputdir . '.tmp.json') . " -o " . escapeshellarg($outputdir . 'index.html') . " --html-report-title=" . escapeshellarg($caption) . " --log-format=" . $format . " - ", $return_value, ['|']);
|
FileDir::safe_exec("grep '" . $monthyear . "' " . escapeshellarg($logfile) . " | goaccess " . $keep_params . " --db-path=" . escapeshellarg($outputdir) . " -o " . escapeshellarg($outputdir . '.tmp.json') . " -o " . escapeshellarg($outputdir . 'index.html') . " --html-report-title=" . escapeshellarg($caption) . " --log-format=" . $format . " --no-parsing-spinner --no-progress - ", $return_value, ['|']);
|
||||||
|
|
||||||
if (file_exists($outputdir . '.tmp.json')) {
|
if (file_exists($outputdir . '.tmp.json')) {
|
||||||
// need jq here because of potentially LARGE json files
|
// need jq here because of potentially LARGE json files
|
||||||
@@ -787,6 +791,8 @@ class TrafficCron extends FroxlorCron
|
|||||||
// 'real' domains and no subdomains which are aliases in the
|
// 'real' domains and no subdomains which are aliases in the
|
||||||
// model-config-file.
|
// model-config-file.
|
||||||
$returnval += self::awstatsDoSingleDomain($singledomain, $outputdir, $current_stamp);
|
$returnval += self::awstatsDoSingleDomain($singledomain, $outputdir, $current_stamp);
|
||||||
|
// kind of a keep-alive-call as this unsets the link which leads to a new connection to the database
|
||||||
|
Database::needRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -43,9 +43,6 @@ class IpAddr
|
|||||||
|
|
||||||
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
if (!isset($system_ipaddress_array[$row['ip']]) && !in_array($row['ip'], $system_ipaddress_array)) {
|
if (!isset($system_ipaddress_array[$row['ip']]) && !in_array($row['ip'], $system_ipaddress_array)) {
|
||||||
if (filter_var($row['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
|
||||||
$row['ip'] = '[' . $row['ip'] . ']';
|
|
||||||
}
|
|
||||||
$system_ipaddress_array[$row['ip']] = $row['ip'];
|
$system_ipaddress_array[$row['ip']] = $row['ip'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ final class Froxlor
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Main version variable
|
// Main version variable
|
||||||
const VERSION = '2.1.1';
|
const VERSION = '2.1.4';
|
||||||
|
|
||||||
// Database version (YYYYMMDDC where C is a daily counter)
|
// Database version (YYYYMMDDC where C is a daily counter)
|
||||||
const DBVERSION = '202312050';
|
const DBVERSION = '202312120';
|
||||||
|
|
||||||
// Distribution branding-tag (used for Debian etc.)
|
// Distribution branding-tag (used for Debian etc.)
|
||||||
const BRANDING = '';
|
const BRANDING = '';
|
||||||
|
|||||||
@@ -151,6 +151,8 @@ class AutoUpdate
|
|||||||
$zip->close();
|
$zip->close();
|
||||||
// success - remove unused archive
|
// success - remove unused archive
|
||||||
@unlink($localArchive);
|
@unlink($localArchive);
|
||||||
|
// reset cached version check
|
||||||
|
Settings::Set('system.updatecheck_data', '');
|
||||||
// wait a bit before we redirect to be sure
|
// wait a bit before we redirect to be sure
|
||||||
sleep(3);
|
sleep(3);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ class Install
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for url manipulation or wrong step
|
// check for url manipulation or wrong step
|
||||||
if ((isset($_SESSION['installation']['stepCompleted']) && ($this->currentStep + 1) > $_SESSION['installation']['stepCompleted'])
|
if ((isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > $_SESSION['installation']['stepCompleted'])
|
||||||
|| (!isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > 0)
|
|| (!isset($_SESSION['installation']['stepCompleted']) && $this->currentStep > 0)
|
||||||
) {
|
) {
|
||||||
$this->currentStep = isset($_SESSION['installation']['stepCompleted']) ? $_SESSION['installation']['stepCompleted'] + 1 : 1;
|
$this->currentStep = isset($_SESSION['installation']['stepCompleted']) ? $_SESSION['installation']['stepCompleted'] + 1 : 1;
|
||||||
@@ -322,6 +322,8 @@ class Install
|
|||||||
$email = $validatedData['admin_email'] ?? '';
|
$email = $validatedData['admin_email'] ?? '';
|
||||||
$password = $validatedData['admin_pass'] ?? '';
|
$password = $validatedData['admin_pass'] ?? '';
|
||||||
$password_confirm = $validatedData['admin_pass_confirm'] ?? '';
|
$password_confirm = $validatedData['admin_pass_confirm'] ?? '';
|
||||||
|
$useadminmailassender = $validatedData['use_admin_email_as_sender'] ?? '1';
|
||||||
|
$senderemail = $validatedData['sender_email'] ?? '';
|
||||||
|
|
||||||
if (!preg_match('/^[^\r\n\t\f\0]*$/D', $name)) {
|
if (!preg_match('/^[^\r\n\t\f\0]*$/D', $name)) {
|
||||||
throw new Exception(lng('error.stringformaterror', ['admin_name']));
|
throw new Exception(lng('error.stringformaterror', ['admin_name']));
|
||||||
@@ -329,6 +331,8 @@ class Install
|
|||||||
throw new Exception(lng('error.loginnameiswrong', [$loginname]));
|
throw new Exception(lng('error.loginnameiswrong', [$loginname]));
|
||||||
} elseif (empty(trim($email)) || !Validate::validateEmail($email)) {
|
} elseif (empty(trim($email)) || !Validate::validateEmail($email)) {
|
||||||
throw new Exception(lng('error.emailiswrong', [$email]));
|
throw new Exception(lng('error.emailiswrong', [$email]));
|
||||||
|
} elseif ((int)$useadminmailassender == 0 && !empty(trim($senderemail)) && !Validate::validateEmail($senderemail)) {
|
||||||
|
throw new Exception(lng('error.emailiswrong', [$senderemail]));
|
||||||
} elseif (empty($password) || $password != $password_confirm) {
|
} elseif (empty($password) || $password != $password_confirm) {
|
||||||
throw new Exception(lng('error.newpasswordconfirmerror'));
|
throw new Exception(lng('error.newpasswordconfirmerror'));
|
||||||
} elseif ($password == $loginname) {
|
} elseif ($password == $loginname) {
|
||||||
|
|||||||
@@ -301,8 +301,8 @@ class Core
|
|||||||
/* continue */
|
/* continue */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (version_compare($db_root->getAttribute(PDO::ATTR_SERVER_VERSION), '10.0.0', '>=')) {
|
if (version_compare($db_root->getAttribute(PDO::ATTR_SERVER_VERSION), '8.0.11', '>=')) {
|
||||||
// mariadb compatibility
|
// mariadb & mysql8
|
||||||
// create user
|
// create user
|
||||||
$stmt = $db_root->prepare("CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED BY :password");
|
$stmt = $db_root->prepare("CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED BY :password");
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
@@ -314,19 +314,6 @@ class Core
|
|||||||
"username" => $username,
|
"username" => $username,
|
||||||
"host" => $access_host
|
"host" => $access_host
|
||||||
]);
|
]);
|
||||||
} elseif (version_compare($db_root->getAttribute(PDO::ATTR_SERVER_VERSION), '8.0.11', '>=')) {
|
|
||||||
// mysql8 compatibility
|
|
||||||
// create user
|
|
||||||
$stmt = $db_root->prepare("CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED WITH mysql_native_password BY :password");
|
|
||||||
$stmt->execute([
|
|
||||||
"password" => $password
|
|
||||||
]);
|
|
||||||
// grant privileges
|
|
||||||
$stmt = $db_root->prepare("GRANT ALL ON `" . $database . "`.* TO :username@:host");
|
|
||||||
$stmt->execute([
|
|
||||||
"username" => $username,
|
|
||||||
"host" => $access_host
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
// grant privileges
|
// grant privileges
|
||||||
$stmt = $db_root->prepare("GRANT ALL PRIVILEGES ON `" . $database . "`.* TO :username@:host IDENTIFIED BY :password");
|
$stmt = $db_root->prepare("GRANT ALL PRIVILEGES ON `" . $database . "`.* TO :username@:host IDENTIFIED BY :password");
|
||||||
@@ -378,7 +365,14 @@ class Core
|
|||||||
|
|
||||||
$mainip = !empty($this->validatedData['serveripv6']) ? $this->validatedData['serveripv6'] : $this->validatedData['serveripv4'];
|
$mainip = !empty($this->validatedData['serveripv6']) ? $this->validatedData['serveripv6'] : $this->validatedData['serveripv4'];
|
||||||
|
|
||||||
$this->updateSetting($upd_stmt, 'admin@' . $this->validatedData['servername'], 'panel', 'adminmail');
|
if ($this->validatedData['use_admin_email_as_sender'] == '1') {
|
||||||
|
$adminmail_value = $this->validatedData['admin_email'];
|
||||||
|
} elseif ($this->validatedData['use_admin_email_as_sender'] == '0' && !empty($this->validatedData['sender_email'])) {
|
||||||
|
$adminmail_value = $this->validatedData['sender_email'];
|
||||||
|
} else {
|
||||||
|
$adminmail_value = 'admin@' . $this->validatedData['servername'];
|
||||||
|
}
|
||||||
|
$this->updateSetting($upd_stmt, $adminmail_value, 'panel', 'adminmail');
|
||||||
$this->updateSetting($upd_stmt, $mainip, 'system', 'ipaddress');
|
$this->updateSetting($upd_stmt, $mainip, 'system', 'ipaddress');
|
||||||
if ($this->validatedData['use_ssl']) {
|
if ($this->validatedData['use_ssl']) {
|
||||||
$this->updateSetting($upd_stmt, 1, 'system', 'use_ssl');
|
$this->updateSetting($upd_stmt, 1, 'system', 'use_ssl');
|
||||||
@@ -576,7 +570,7 @@ class Core
|
|||||||
'password' => password_hash($this->validatedData['admin_pass'], PASSWORD_DEFAULT),
|
'password' => password_hash($this->validatedData['admin_pass'], PASSWORD_DEFAULT),
|
||||||
'adminname' => $this->validatedData['admin_name'],
|
'adminname' => $this->validatedData['admin_name'],
|
||||||
'email' => $this->validatedData['admin_email'],
|
'email' => $this->validatedData['admin_email'],
|
||||||
'deflang' => 'en' // TODO: set lanuage
|
'deflang' => 'en' // TODO: set language
|
||||||
];
|
];
|
||||||
$ins_stmt = $db_user->prepare("
|
$ins_stmt = $db_user->prepare("
|
||||||
INSERT INTO `" . TABLE_PANEL_ADMINS . "` SET
|
INSERT INTO `" . TABLE_PANEL_ADMINS . "` SET
|
||||||
|
|||||||
@@ -220,8 +220,11 @@ class PhpHelper
|
|||||||
if (is_dir($data_dirname)) {
|
if (is_dir($data_dirname)) {
|
||||||
$data_dirhandle = opendir($data_dirname);
|
$data_dirhandle = opendir($data_dirname);
|
||||||
while (false !== ($data_filename = readdir($data_dirhandle))) {
|
while (false !== ($data_filename = readdir($data_dirhandle))) {
|
||||||
if ($data_filename != '.' && $data_filename != '..' && $data_filename != '' && substr($data_filename,
|
if ($data_filename != '.'
|
||||||
-4) == '.php') {
|
&& $data_filename != '..'
|
||||||
|
&& $data_filename != ''
|
||||||
|
&& substr($data_filename, -4) == '.php'
|
||||||
|
) {
|
||||||
$data_files[] = $data_dirname . $data_filename;
|
$data_files[] = $data_dirname . $data_filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -458,6 +461,10 @@ class PhpHelper
|
|||||||
'directory_password',
|
'directory_password',
|
||||||
'ftp_password',
|
'ftp_password',
|
||||||
'mysql_password',
|
'mysql_password',
|
||||||
|
'mysql_root_pass',
|
||||||
|
'mysql_unprivileged_pass',
|
||||||
|
'admin_pass',
|
||||||
|
'admin_pass_confirm',
|
||||||
];
|
];
|
||||||
if (!empty($global)) {
|
if (!empty($global)) {
|
||||||
$tmp = $global;
|
$tmp = $global;
|
||||||
@@ -557,4 +564,17 @@ class PhpHelper
|
|||||||
}
|
}
|
||||||
return $tab . $str;
|
return $tab . $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function array_merge_recursive_distinct(array &$array1, array &$array2)
|
||||||
|
{
|
||||||
|
$merged = $array1;
|
||||||
|
foreach ($array2 as $key => &$value) {
|
||||||
|
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
|
||||||
|
$merged[$key] = self::array_merge_recursive_distinct($merged[$key], $value);
|
||||||
|
} else {
|
||||||
|
$merged[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $merged;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class Domain
|
|||||||
return lng('domains.aliasdomain') . ' ' . $attributes['fields']['aliasdomain'];
|
return lng('domains.aliasdomain') . ' ' . $attributes['fields']['aliasdomain'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function domainExternalLinkInfo(array $attributes)
|
public static function domainExternalLinkInfo(array $attributes): string
|
||||||
{
|
{
|
||||||
$result = '';
|
$result = '';
|
||||||
if ($attributes['fields']['parentdomainid'] != 0) {
|
if ($attributes['fields']['parentdomainid'] != 0) {
|
||||||
@@ -89,7 +89,11 @@ class Domain
|
|||||||
}
|
}
|
||||||
$result .= '<a href="http://' . $attributes['data'] . '" target="_blank">' . $attributes['data'] . '</a>';
|
$result .= '<a href="http://' . $attributes['data'] . '" target="_blank">' . $attributes['data'] . '</a>';
|
||||||
// check for statistics if parentdomainid==0 to show stats-link for customers
|
// check for statistics if parentdomainid==0 to show stats-link for customers
|
||||||
if ((int)UI::getCurrentUser()['adminsession'] == 0 && $attributes['fields']['parentdomainid'] == 0 && $attributes['fields']['deactivated'] == 0) {
|
if ((int)UI::getCurrentUser()['adminsession'] == 0
|
||||||
|
&& $attributes['fields']['parentdomainid'] == 0
|
||||||
|
&& $attributes['fields']['deactivated'] == 0
|
||||||
|
&& preg_match('/^https?:\/\/(.*)/i', $attributes['fields']['documentroot']) == false
|
||||||
|
) {
|
||||||
$statsapp = Settings::Get('system.traffictool');
|
$statsapp = Settings::Get('system.traffictool');
|
||||||
$result .= ' <a href="http://' . $attributes['data'] . '/' . $statsapp . '" rel="external" target="_blank" title="' . lng('domains.statstics') . '"><i class="fa-solid fa-chart-line text-secondary"></i></a>';
|
$result .= ' <a href="http://' . $attributes['data'] . '/' . $statsapp . '" rel="external" target="_blank" title="' . lng('domains.statstics') . '"><i class="fa-solid fa-chart-line text-secondary"></i></a>';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ class Form
|
|||||||
{
|
{
|
||||||
$returnvalue = [];
|
$returnvalue = [];
|
||||||
if (is_array($fielddata) && isset($fielddata['type']) && $fielddata['type'] == 'select') {
|
if (is_array($fielddata) && isset($fielddata['type']) && $fielddata['type'] == 'select') {
|
||||||
if ((!isset($fielddata['select_var']) || !is_array($fielddata['select_var']) || empty($fielddata['select_var'])) && (isset($fielddata['option_options_method']))) {
|
if ((!is_array($fielddata['select_var']) || empty($fielddata['select_var'])) && (isset($fielddata['option_options_method']))) {
|
||||||
$returnvalue['select_var'] = call_user_func($fielddata['option_options_method']);
|
$returnvalue['select_var'] = call_user_func($fielddata['option_options_method']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,8 +236,8 @@ class Form
|
|||||||
if (\Froxlor\Validate\Form::validateFieldDefinition($groupdetails)) {
|
if (\Froxlor\Validate\Form::validateFieldDefinition($groupdetails)) {
|
||||||
// Prefetch form fields
|
// Prefetch form fields
|
||||||
foreach ($groupdetails['fields'] as $fieldname => $fielddetails) {
|
foreach ($groupdetails['fields'] as $fieldname => $fielddetails) {
|
||||||
if (!$only_enabledisable || ($only_enabledisable && isset($fielddetails['overview_option']))) {
|
if (!$only_enabledisable || isset($fielddetails['overview_option'])) {
|
||||||
$groupdetails['fields'][$fieldname] = self::arrayMergePrefix($fielddetails, $fielddetails['type'], self::prefetchFormFieldData($fieldname, $fielddetails));
|
$groupdetails['fields'][$fieldname] = array_merge($fielddetails, self::prefetchFormFieldData($fieldname, $fielddetails));
|
||||||
$form['groups'][$groupname]['fields'][$fieldname] = $groupdetails['fields'][$fieldname];
|
$form['groups'][$groupname]['fields'][$fieldname] = $groupdetails['fields'][$fieldname];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,7 +347,7 @@ class Form
|
|||||||
if (\Froxlor\Validate\Form::validateFieldDefinition($groupdetails)) {
|
if (\Froxlor\Validate\Form::validateFieldDefinition($groupdetails)) {
|
||||||
// Save fields
|
// Save fields
|
||||||
foreach ($groupdetails['fields'] as $fieldname => $fielddetails) {
|
foreach ($groupdetails['fields'] as $fieldname => $fielddetails) {
|
||||||
if (!$only_enabledisable || ($only_enabledisable && isset($fielddetails['overview_option']))) {
|
if (!$only_enabledisable || (isset($fielddetails['overview_option']))) {
|
||||||
if (isset($changed_fields[$fieldname])) {
|
if (isset($changed_fields[$fieldname])) {
|
||||||
if (($saved_field = self::saveFormField($fieldname, $fielddetails, self::manipulateFormFieldData($fieldname, $fielddetails, $changed_fields[$fieldname]))) !== false) {
|
if (($saved_field = self::saveFormField($fieldname, $fielddetails, self::manipulateFormFieldData($fieldname, $fielddetails, $changed_fields[$fieldname]))) !== false) {
|
||||||
$saved_fields = array_merge($saved_fields, $saved_field);
|
$saved_fields = array_merge($saved_fields, $saved_field);
|
||||||
@@ -364,24 +364,7 @@ class Form
|
|||||||
// Save form
|
// Save form
|
||||||
return self::saveForm($form, $saved_fields);
|
return self::saveForm($form, $saved_fields);
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
|
|
||||||
private static function arrayMergePrefix($array1, $key_prefix, $array2)
|
|
||||||
{
|
|
||||||
if (is_array($array1) && is_array($array2)) {
|
|
||||||
if ($key_prefix != '') {
|
|
||||||
foreach ($array2 as $key => $value) {
|
|
||||||
$array1[$key_prefix . '_' . $key] = $value;
|
|
||||||
unset($array2[$key]);
|
|
||||||
}
|
|
||||||
unset($array2);
|
|
||||||
return $array1;
|
|
||||||
} else {
|
|
||||||
return array_merge($array1, $array2);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return $array1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getFormFieldData($fieldname, $fielddata, &$input)
|
public static function getFormFieldData($fieldname, $fielddata, &$input)
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ class Validate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// special case where localhost ip is allowed (mysql-access-hosts for example)
|
// special case where localhost ip is allowed (mysql-access-hosts for example)
|
||||||
if ($allow_localhost && $ip == '127.0.0.1') {
|
if ($allow_localhost && ($ip == '127.0.0.1' || $ip == '::1')) {
|
||||||
return $ip . $cidr;
|
return $ip . $cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1556,7 +1556,7 @@ noc: root
|
|||||||
security: root
|
security: root
|
||||||
|
|
||||||
# change this to a valid e-mail address you can access
|
# change this to a valid e-mail address you can access
|
||||||
root: root@<SERVERNAME>
|
root: <ADMIN_MAIL>
|
||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@@ -1556,7 +1556,7 @@ noc: root
|
|||||||
security: root
|
security: root
|
||||||
|
|
||||||
# change this to a valid e-mail address you can access
|
# change this to a valid e-mail address you can access
|
||||||
root: root@<SERVERNAME>
|
root: <ADMIN_MAIL>
|
||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@@ -1585,7 +1585,7 @@ noc: root
|
|||||||
security: root
|
security: root
|
||||||
|
|
||||||
# change this to a valid e-mail address you can access
|
# change this to a valid e-mail address you can access
|
||||||
root: root@<SERVERNAME>
|
root: <ADMIN_MAIL>
|
||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@@ -1541,7 +1541,7 @@ noc: root
|
|||||||
security: root
|
security: root
|
||||||
|
|
||||||
# change this to a valid e-mail address you can access
|
# change this to a valid e-mail address you can access
|
||||||
root: root@<SERVERNAME>
|
root: <ADMIN_MAIL>
|
||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@@ -1585,7 +1585,7 @@ noc: root
|
|||||||
security: root
|
security: root
|
||||||
|
|
||||||
# change this to a valid e-mail address you can access
|
# change this to a valid e-mail address you can access
|
||||||
root: root@<SERVERNAME>
|
root: <ADMIN_MAIL>
|
||||||
]]>
|
]]>
|
||||||
</content>
|
</content>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ return [
|
|||||||
'label' => lng('login.password'),
|
'label' => lng('login.password'),
|
||||||
'type' => 'password',
|
'type' => 'password',
|
||||||
'autocomplete' => 'off',
|
'autocomplete' => 'off',
|
||||||
'placeholder' => lng('admin.username_default_msg'),
|
'placeholder' => lng('admin.password_default_msg'),
|
||||||
'next_to' => [
|
'next_to' => [
|
||||||
'new_customer_password_suggestion' => [
|
'new_customer_password_suggestion' => [
|
||||||
'next_to_prefix' => lng('customer.generated_pwd') . ':',
|
'next_to_prefix' => lng('customer.generated_pwd') . ':',
|
||||||
|
|||||||
@@ -143,6 +143,18 @@ return [
|
|||||||
'mandatory' => true,
|
'mandatory' => true,
|
||||||
'value' => old('admin_email', null, 'installation'),
|
'value' => old('admin_email', null, 'installation'),
|
||||||
],
|
],
|
||||||
|
'use_admin_email_as_sender' => [
|
||||||
|
'label' => lng('install.admin.use_admin_email_as_sender'),
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'value' => '1',
|
||||||
|
'checked' => old('use_admin_email_as_sender', '1', 'installation'),
|
||||||
|
],
|
||||||
|
'sender_email' => [
|
||||||
|
'label' => lng('serversettings.adminmail.title'),
|
||||||
|
'placeholder' => lng('install.admin.use_autogenerated_email_as_sender'),
|
||||||
|
'type' => 'email',
|
||||||
|
'value' => old('sender_email', null, 'installation'),
|
||||||
|
],
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'step3' => [
|
'step3' => [
|
||||||
|
|||||||
@@ -112,9 +112,14 @@ function vite($basehref, array $filenames): string
|
|||||||
$assetDirectory = '/templates/' . $matches[1] . '/build/';
|
$assetDirectory = '/templates/' . $matches[1] . '/build/';
|
||||||
$viteManifest = dirname(__DIR__) . $assetDirectory . '/manifest.json';
|
$viteManifest = dirname(__DIR__) . $assetDirectory . '/manifest.json';
|
||||||
$manifest = json_decode(file_get_contents($viteManifest), true);
|
$manifest = json_decode(file_get_contents($viteManifest), true);
|
||||||
|
if (!empty($manifest[$filename]['file'])) {
|
||||||
$links[] = $basehref . ltrim($assetDirectory, '/') . $manifest[$filename]['file'];
|
$links[] = $basehref . ltrim($assetDirectory, '/') . $manifest[$filename]['file'];
|
||||||
} else {
|
} else {
|
||||||
$links = $filenames;
|
// additional asset from config.json that was not prebuilt on release (e.g. custom.css)
|
||||||
|
$links[] = $filename;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$links[] = $filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ if ($req_host != Settings::Get('system.hostname') &&
|
|||||||
(!empty(Settings::Get('system.froxloraliases')) && !in_array($req_host, array_map('trim', explode(',', Settings::Get('system.froxloraliases')))))
|
(!empty(Settings::Get('system.froxloraliases')) && !in_array($req_host, array_map('trim', explode(',', Settings::Get('system.froxloraliases')))))
|
||||||
)) {
|
)) {
|
||||||
// not the froxlor system-hostname, show info page for domains not configured in froxlor
|
// not the froxlor system-hostname, show info page for domains not configured in froxlor
|
||||||
$redirect_file = FileDir::getUnknownDomainTemplate($req_host);
|
$redirect_file = FileDir::getUnknownDomainTemplate($req_host ?? "non-detectable http-host");
|
||||||
header('Location: '.$redirect_file);
|
header('Location: '.$redirect_file);
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
@@ -225,7 +225,7 @@ if (is_array($_themeoptions) && (!array_key_exists('variants', $_themeoptions) |
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('global', $_themeoptions)) {
|
if (array_key_exists('global', $_themeoptions)) {
|
||||||
$_themeoptions['variants'][$themevariant] = array_merge_recursive($_themeoptions['variants'][$themevariant], $_themeoptions['global']);
|
$_themeoptions['variants'][$themevariant] = PhpHelper::array_merge_recursive_distinct($_themeoptions['global'], $_themeoptions['variants'][$themevariant]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for custom header-graphic
|
// check for custom header-graphic
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ return [
|
|||||||
'field' => 'domains',
|
'field' => 'domains',
|
||||||
'callback' => [PHPConf::class, 'domainList'],
|
'callback' => [PHPConf::class, 'domainList'],
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
|
'sortable' => false,
|
||||||
],
|
],
|
||||||
'fpmdesc' => [
|
'fpmdesc' => [
|
||||||
'label' => lng('admin.phpsettings.fpmdesc'),
|
'label' => lng('admin.phpsettings.fpmdesc'),
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ return [
|
|||||||
'customer_add' => 'Kunden anlegen',
|
'customer_add' => 'Kunden anlegen',
|
||||||
'customer_edit' => 'Kunden bearbeiten',
|
'customer_edit' => 'Kunden bearbeiten',
|
||||||
'username_default_msg' => 'Leer lassen für automatische Benutzername-Vergabe',
|
'username_default_msg' => 'Leer lassen für automatische Benutzername-Vergabe',
|
||||||
|
'password_default_msg' => 'Leer lassen für Passwortgenerierung',
|
||||||
'domains' => 'Domains',
|
'domains' => 'Domains',
|
||||||
'domain_add' => 'Domain anlegen',
|
'domain_add' => 'Domain anlegen',
|
||||||
'domain_edit' => 'Domain bearbeiten',
|
'domain_edit' => 'Domain bearbeiten',
|
||||||
@@ -1315,6 +1316,7 @@ Vielen Dank, Ihr Administrator',
|
|||||||
'certificate_reallydelete' => 'Wollen Sie diese Zertifikat wirklich löschen?',
|
'certificate_reallydelete' => 'Wollen Sie diese Zertifikat wirklich löschen?',
|
||||||
'cache_reallydelete' => 'Wollen Sie den Cache wirklich leeren?',
|
'cache_reallydelete' => 'Wollen Sie den Cache wirklich leeren?',
|
||||||
'please_enter_otp' => 'Bitte 2FA Code eingeben',
|
'please_enter_otp' => 'Bitte 2FA Code eingeben',
|
||||||
|
'admin_mysqlserver_reallydelete' => 'Wollen Sie wirklich diesen MySQL-Server löschen?',
|
||||||
],
|
],
|
||||||
'serversettings' => [
|
'serversettings' => [
|
||||||
'session_timeout' => [
|
'session_timeout' => [
|
||||||
@@ -2252,6 +2254,8 @@ Vielen Dank, Ihr Administrator',
|
|||||||
'top' => 'Admin Konto',
|
'top' => 'Admin Konto',
|
||||||
'title' => 'Erstellen des Haupt-Administrators.',
|
'title' => 'Erstellen des Haupt-Administrators.',
|
||||||
'description' => 'Dieser Benutzer erhält alle Berechtigungen zur Anpassungen von Einstellungen und Erstellen/Bearbeiten/Löschen von Resourcen wie Kunden, Domains, etc.',
|
'description' => 'Dieser Benutzer erhält alle Berechtigungen zur Anpassungen von Einstellungen und Erstellen/Bearbeiten/Löschen von Resourcen wie Kunden, Domains, etc.',
|
||||||
|
'use_admin_email_as_sender' => 'Verwende die oben angegebene E-Mail-Adresse als Absenderadresse. Wenn die Option deaktiviert ist, geben Sie unten bitte eine Absenderadresse an.',
|
||||||
|
'use_autogenerated_email_as_sender' => 'Leer lassen für Standard: admin@servername',
|
||||||
],
|
],
|
||||||
'system' => [
|
'system' => [
|
||||||
'top' => 'System Setup',
|
'top' => 'System Setup',
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ return [
|
|||||||
'customer_add' => 'Create customer',
|
'customer_add' => 'Create customer',
|
||||||
'customer_edit' => 'Edit customer',
|
'customer_edit' => 'Edit customer',
|
||||||
'username_default_msg' => 'Leave empty for autogenerated value',
|
'username_default_msg' => 'Leave empty for autogenerated value',
|
||||||
|
'password_default_msg' => 'Autogenerated if empty',
|
||||||
'domains' => 'Domains',
|
'domains' => 'Domains',
|
||||||
'domain_add' => 'Create domain',
|
'domain_add' => 'Create domain',
|
||||||
'domain_edit' => 'Edit domain',
|
'domain_edit' => 'Edit domain',
|
||||||
@@ -1430,6 +1431,7 @@ Yours sincerely, your administrator',
|
|||||||
'certificate_reallydelete' => 'Do you really want to delete this certificate?',
|
'certificate_reallydelete' => 'Do you really want to delete this certificate?',
|
||||||
'cache_reallydelete' => 'Do you really want to clear the cache?',
|
'cache_reallydelete' => 'Do you really want to clear the cache?',
|
||||||
'please_enter_otp' => 'Please enter 2FA code',
|
'please_enter_otp' => 'Please enter 2FA code',
|
||||||
|
'admin_mysqlserver_reallydelete' => 'Do you really want to delete this MySQL-server?',
|
||||||
],
|
],
|
||||||
'redirect_desc' => [
|
'redirect_desc' => [
|
||||||
'rc_default' => 'default',
|
'rc_default' => 'default',
|
||||||
@@ -2388,6 +2390,8 @@ Yours sincerely, your administrator',
|
|||||||
'top' => 'Admin user',
|
'top' => 'Admin user',
|
||||||
'title' => 'Let\'s create the main administrator user.',
|
'title' => 'Let\'s create the main administrator user.',
|
||||||
'description' => 'This user will be granted all privileges to adjust settings and add/update/delete resources like customers, domains, etc.',
|
'description' => 'This user will be granted all privileges to adjust settings and add/update/delete resources like customers, domains, etc.',
|
||||||
|
'use_admin_email_as_sender' => 'Use the email address above as sender address. If unchecked, please specify a sender address below.',
|
||||||
|
'use_autogenerated_email_as_sender' => 'Leave empty for default: admin@servername',
|
||||||
],
|
],
|
||||||
'system' => [
|
'system' => [
|
||||||
'top' => 'System setup',
|
'top' => 'System setup',
|
||||||
|
|||||||
@@ -8,18 +8,18 @@ export default function () {
|
|||||||
rules: {
|
rules: {
|
||||||
'name': {
|
'name': {
|
||||||
required: function () {
|
required: function () {
|
||||||
return $('#company').val().length === 0 || $('#firstname').val().length > 0;
|
return $('#company').val().trim().length === 0 || $('#firstname').val().trim().length > 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'firstname': {
|
'firstname': {
|
||||||
required: function () {
|
required: function () {
|
||||||
return $('#company').val().length === 0 || $('#name').val().length > 0;
|
return $('#company').val().trim().length === 0 || $('#name').val().trim().length > 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'company': {
|
'company': {
|
||||||
required: function () {
|
required: function () {
|
||||||
return $('#name').val().length === 0
|
return $('#name').val().trim().length === 0
|
||||||
&& $('#firstname').val().length === 0;
|
&& $('#firstname').val().trim().length === 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
background-color: $body-tertiary-bg;
|
background-color: $body-tertiary-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-floating > .form-control::placeholder {
|
||||||
|
color: revert;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-floating > .form-control:not(:focus)::placeholder {
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
@include color-mode(dark) {
|
@include color-mode(dark) {
|
||||||
.formfield {
|
.formfield {
|
||||||
border-bottom: $border-color-dark solid 1px;
|
border-bottom: $border-color-dark solid 1px;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"global": {
|
"global": {
|
||||||
"css": [
|
"css": [
|
||||||
"assets/css/custom.css",
|
"assets/scss/app.scss",
|
||||||
"assets/scss/app.scss"
|
"assets/css/custom.css"
|
||||||
],
|
],
|
||||||
"js": [
|
"js": [
|
||||||
"assets/js/app.js",
|
"assets/js/app.js",
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% set field = field|merge({'type':'file'}) %}
|
{% set field = field|merge({'type':'file'})|merge({'value':''}) %}
|
||||||
{{ _self.input(id, field) }}
|
{{ _self.input(id, field) }}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
aria-valuemin="0" aria-valuemax="{{ apcuinfo.mem_avail }}">
|
aria-valuemin="0" aria-valuemax="{{ apcuinfo.mem_avail }}">
|
||||||
<div class="progress-bar bg-success" style="width: {{ apcuinfo.mem_used_percentage }}%"></div>
|
<div class="progress-bar bg-success" style="width: {{ apcuinfo.mem_used_percentage }}%"></div>
|
||||||
<small
|
<small
|
||||||
class="justify-content-center d-flex position-absolute w-100 text-dark">{{ apcuinfo.mem_used_percentage }}
|
class="justify-content-center d-flex position-absolute w-100">{{ apcuinfo.mem_used_percentage }}
|
||||||
%</small>
|
%</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user