Compare commits

...

20 Commits
2.0.1 ... 2.0.7

Author SHA1 Message Date
Michael Kaufmann
80e442e396 set version to 2.0.7
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-10 22:15:57 +01:00
Michael Kaufmann
489ad375bd ensure latest userdata.inc.php layout for updaters/users of old format
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-10 16:54:20 +01:00
Michael Kaufmann
c420196e73 check explicitly for template existence and try to use default theme as fallback; fixes #1071
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-10 16:53:36 +01:00
Michael Kaufmann
cc6d8d5f8b fix login if non-standard ports are used for froxlor vhost
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-10 12:43:04 +01:00
Michael Kaufmann
24f47bc58b set version to 2.0.6
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-09 10:09:15 +01:00
Michael Kaufmann
c769c074e0 add Google CA to available acme.sh providers; fixes #1065
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-09 10:00:08 +01:00
dependabot[bot]
2ecb8eb034 Bump json5 from 1.0.1 to 1.0.2 (#1069)
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-09 09:51:52 +01:00
Michael Kaufmann
6827c100c3 fix updating email account password-hashes in updater
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-09 09:50:51 +01:00
Michael Kaufmann
c402acd1bd disable correct mod_php in bionic-config-templates when fcgid/php-fpm is selected
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-09 09:25:29 +01:00
Michael Kaufmann
c4ec2509fa fix resetting of isemaildomain-flag of subdomains when nothing changed; fixes #1067
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-09 09:24:22 +01:00
Michael Kaufmann
0f382586ce set version to 2.0.5
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 23:24:43 +01:00
Michael Kaufmann
9c2f12ecb1 mysql-remote-server fixes
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 23:20:31 +01:00
Michael Kaufmann
12da117cab fix chmod() command in compatibility cronjob for updaters
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 20:20:44 +01:00
Michael Kaufmann
ef48f4b48e set version to 2.0.3
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 19:44:07 +01:00
Michael Kaufmann
aae6db52b5 temporarily change innodb_strict_mode to run table updates (shorten fields)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 19:36:05 +01:00
Michael Kaufmann
fb7d65d645 need pagination-context for sortfields; only disable pagination-code on view
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 19:01:10 +01:00
Michael Kaufmann
3b9c60e985 fix pagination when pagination is diabled (entries per page = 0)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 18:52:58 +01:00
Michael Kaufmann
452df60866 set version to 2.0.2
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 17:58:42 +01:00
Michael Kaufmann
7ce7123756 fix sql text defaults in updater
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 17:34:58 +01:00
Michael Kaufmann
d42072e3ad re-enable/fix sortable tablelisting flag
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-01-08 17:25:19 +01:00
27 changed files with 195 additions and 77 deletions

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@ install/update.log
install/*.json
lib/userdata.inc.php
lib/userdata.inc.php.bak
lib/config.inc.php
logs/*
!logs/index.html
.buildpath

View File

@@ -180,7 +180,9 @@ return [
'letsencrypt' => 'Let\'s Encrypt (Live)',
'buypass_test' => 'Buypass (Test / Staging)',
'buypass' => 'Buypass (Live)',
'zerossl' => 'ZeroSSL (Live)'
'zerossl' => 'ZeroSSL (Live)',
'google' => 'Google (Live)',
'google_test' => 'Google (Test / Staging)',
],
'save_method' => 'storeSettingField'
],

View File

@@ -43,12 +43,6 @@ use PHPMailer\PHPMailer\PHPMailer;
const AREA = 'admin';
require __DIR__ . '/lib/init.php';
// get sql-root access data
Database::needRoot(true);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);
if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
$settings_data = PhpHelper::loadConfigArrayDir('./actions/admin/settings/');
Settings::loadSettingsInto($settings_data);

View File

@@ -59,7 +59,6 @@ if ($page == 'overview' || $page == 'domains') {
$domain_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.domains.php';
$collection = (new Collection(SubDomains::class, $userinfo))
->withPagination($domain_list_data['domain_list']['columns'], $domain_list_data['domain_list']['default_sorting']);
$parentDomainCollection = (new Collection(SubDomains::class, $userinfo, ['sql_search' => ['d.parentdomainid' => 0]]));
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -92,7 +92,7 @@ if ($page == 'overview' || $page == 'mysqls') {
$result = json_decode($json_result, true)['data'];
if (isset($result['databasename']) && $result['databasename'] != '') {
Database::needRoot(true, $result['dbserver']);
Database::needRoot(true, $result['dbserver'], false);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);

View File

@@ -67,6 +67,11 @@ if (!empty($errid)) {
$mail_body .= "User-Area: " . AREA . "\n";
$mail_body .= "Froxlor-version: " . Froxlor::VERSION . "\n";
$mail_body .= "DB-version: " . Froxlor::DBVERSION . "\n\n";
try {
$mail_body .= "Database: " . Database::getAttribute(PDO::ATTR_SERVER_VERSION);
} catch (\Exception $e) {
/* ignore */
}
$mail_body .= "End of report";
$mail_html = nl2br($mail_body);

View File

@@ -225,7 +225,7 @@ CREATE TABLE `panel_customers` (
`allowed_mysqlserver` text NOT NULL,
PRIMARY KEY (`customerid`),
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_databases`;
@@ -696,7 +696,7 @@ opcache.validate_timestamps'),
('system', 'distribution', ''),
('system', 'update_channel', 'stable'),
('system', 'updatecheck_data', ''),
('system', 'update_notify_last', '2.0.1'),
('system', 'update_notify_last', '2.0.7'),
('system', 'traffictool', 'goaccess'),
('api', 'enabled', '0'),
('2fa', 'enabled', '1'),
@@ -740,7 +740,7 @@ opcache.validate_timestamps'),
('panel', 'logo_overridetheme', '0'),
('panel', 'logo_overridecustom', '0'),
('panel', 'settings_mode', '0'),
('panel', 'version', '2.0.1'),
('panel', 'version', '2.0.7'),
('panel', 'db_version', '202212060');

View File

@@ -67,9 +67,10 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;";
Database::query($sql);
// new customer allowed_mysqlserver field
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `allowed_mysqlserver` text NOT NULL default '[0]';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE COLUMN `allowed_phpconfigs` `allowed_phpconfigs` text NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ROW_FORMAT=DYNAMIC;");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE COLUMN `customernumber` `customernumber` varchar(100) NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE COLUMN `allowed_phpconfigs` `allowed_phpconfigs` text NOT NULL;");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `allowed_mysqlserver` text NOT NULL;");
$has_customer_table_update_200 = true;
// ftp_users adjustments
Database::query("ALTER TABLE `" . TABLE_FTP_USERS . "` CHANGE COLUMN `password` `password` varchar(255) NOT NULL default '';");
@@ -182,10 +183,10 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
Update::lastStepStatus(0);
Update::showUpdateStep("Updating email account password-hashes");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = REPLACE(`password`, '$1$', '{MD5-CRYPT}$1$') WHERE SUBSTRING(`password`, 1, 3) = '$1$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = REPLACE(`password`, '$5$', '{SHA256-CRYPT}$5$') WHERE SUBSTRING(`password`, 1, 3) = '$5$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = REPLACE(`password`, '$6$', '{SHA512-CRYPT}$6$') WHERE SUBSTRING(`password`, 1, 3) = '$6$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = REPLACE(`password`, '$2y$', '{BLF-CRYPT}$2y$') WHERE SUBSTRING(`password`, 1, 4) = '$2y$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$1$', '{MD5-CRYPT}$1$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$1$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$5$', '{SHA256-CRYPT}$5$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$5$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$6$', '{SHA512-CRYPT}$6$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$6$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$2y$', '{BLF-CRYPT}$2y$') WHERE SUBSTRING(`password_enc`, 1, 4) = '$2y$'");
Update::lastStepStatus(0);
Froxlor::updateToVersion($update_to);
@@ -210,7 +211,7 @@ if (Froxlor::isDatabaseVersion('202211030')) {
$newCronBin = Froxlor::getInstallDir().'/bin/froxlor-cli';
$compCron = <<<EOF
<?php
chmod($newCronBin, 0755);
chmod('$newCronBin', 0755);
// re-create cron.d configuration file
exec('$newCronBin froxlor:cron -r 99');
exit;
@@ -240,3 +241,63 @@ if (Froxlor::isFroxlorVersion('2.0.0')) {
Froxlor::updateToVersion('2.0.1');
}
if (Froxlor::isFroxlorVersion('2.0.1')) {
Update::showUpdateStep("Updating from 2.0.1 to 2.0.2", false);
Froxlor::updateToVersion('2.0.2');
}
if (Froxlor::isFroxlorVersion('2.0.2')) {
Update::showUpdateStep("Updating from 2.0.2 to 2.0.3", false);
Froxlor::updateToVersion('2.0.3');
}
if (Froxlor::isFroxlorVersion('2.0.3')) {
Update::showUpdateStep("Updating from 2.0.3 to 2.0.4", false);
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
// check if compat. cronjob still exists (most likely didn't run successfully b/c of error from former 2.0 release)
if (@file_exists($complete_filedir.'/froxlor_master_cronjob.php')) {
Update::showUpdateStep("Adjusting backward compatibility for cronjob");
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
$compCron = <<<EOF
<?php
chmod('$newCronBin', 0755);
// re-create cron.d configuration file
exec('$newCronBin froxlor:cron -r 99');
exit;
EOF;
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
Update::lastStepStatus(0);
}
Froxlor::updateToVersion('2.0.4');
}
if (Froxlor::isFroxlorVersion('2.0.4')) {
Update::showUpdateStep("Updating from 2.0.4 to 2.0.5", false);
Froxlor::updateToVersion('2.0.5');
}
if (Froxlor::isFroxlorVersion('2.0.5')) {
Update::showUpdateStep("Updating from 2.0.5 to 2.0.6", false);
Update::showUpdateStep("Updating possible missing email account password-hashes");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$1$', '{MD5-CRYPT}$1$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$1$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$5$', '{SHA256-CRYPT}$5$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$5$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$6$', '{SHA512-CRYPT}$6$') WHERE SUBSTRING(`password_enc`, 1, 3) = '$6$'");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password_enc` = REPLACE(`password_enc`, '$2y$', '{BLF-CRYPT}$2y$') WHERE SUBSTRING(`password_enc`, 1, 4) = '$2y$'");
Update::lastStepStatus(0);
Froxlor::updateToVersion('2.0.6');
}
if (Froxlor::isFroxlorVersion('2.0.6')) {
Update::showUpdateStep("Updating from 2.0.6 to 2.0.7", false);
Update::showUpdateStep("Correcting allowed_mysqlserver for customers");
Database::query("UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `allowed_mysqlserver` = '[0]' WHERE `allowed_mysqlserver` = ''");
Update::lastStepStatus(0);
Froxlor::updateToVersion('2.0.7');
}

View File

@@ -90,7 +90,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
// validate whether the dbserver exists
$dbserver = Validate::validate($dbserver, html_entity_decode(lng('mysql.mysql_server')), '/^[0-9]+$/', '', 0, true);
Database::needRoot(true, $dbserver);
Database::needRoot(true, $dbserver, false);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);
@@ -150,7 +150,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
$pma = Settings::Get('panel.phpmyadmin_url');
}
Database::needRoot(true, $dbserver);
Database::needRoot(true, $dbserver, false);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);
@@ -287,7 +287,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
}
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
Database::needRoot(true, $result['dbserver']);
Database::needRoot(true, $result['dbserver'], false);
$mbdata_stmt = Database::prepare("
SELECT SUM(data_length + index_length) as MB FROM information_schema.TABLES
WHERE table_schema = :table_schema
@@ -364,7 +364,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
}
// Begin root-session
Database::needRoot(true, $result['dbserver']);
Database::needRoot(true, $result['dbserver'], false);
$dbmgr = new DbManager($this->logger());
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$dbmgr->getManager()->grantPrivilegesTo($result['databasename'], $password, $mysql_access_host, false, true);
@@ -449,7 +449,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
'dbserver' => $_dbserver['dbserver']
], $query_fields), true, true);
// Begin root-session
Database::needRoot(true, $_dbserver['dbserver']);
Database::needRoot(true, $_dbserver['dbserver'], false);
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$mbdata_stmt = Database::prepare("
SELECT SUM(data_length + index_length) as MB FROM information_schema.TABLES
@@ -536,7 +536,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
$id = $result['id'];
// Begin root-session
Database::needRoot(true, $result['dbserver']);
Database::needRoot(true, $result['dbserver'], false);
$dbm = new DbManager($this->logger());
$dbm->getManager()->deleteDatabase($result['databasename']);
Database::needRoot(false);

View File

@@ -701,10 +701,12 @@ class SubDomains extends ApiCommand implements ResourceEntity
$wwwserveralias = ($selectserveralias == '1') ? '1' : '0';
// if allowed, check for 'is email domain'-flag
if ($result['parentdomainid'] != '0' && ($result['subcanemaildomain'] == '1' || $result['subcanemaildomain'] == '2') && $isemaildomain != $result['isemaildomain']) {
$isemaildomain = intval($isemaildomain);
} elseif ($result['parentdomainid'] != '0') {
$isemaildomain = $result['subcanemaildomain'] == '3' ? 1 : 0;
if ($isemaildomain != $result['isemaildomain']) {
if ($result['parentdomainid'] != '0' && ($result['subcanemaildomain'] == '1' || $result['subcanemaildomain'] == '2')) {
$isemaildomain = intval($isemaildomain);
} elseif ($result['parentdomainid'] != '0') {
$isemaildomain = $result['subcanemaildomain'] == '3' ? 1 : 0;
}
}
// check changes of openbasedir-path variable

View File

@@ -46,7 +46,9 @@ class AcmeSh extends FroxlorCron
'letsencrypt_test' => "https://acme-staging-v02.api.letsencrypt.org/directory",
'buypass' => "https://api.buypass.com/acme/directory",
'buypass_test' => "https://api.test4.buypass.no/acme/directory",
'zerossl' => "https://acme.zerossl.com/v2/DV90"
'zerossl' => "https://acme.zerossl.com/v2/DV90",
'google' => "https://dv.acme-v02.api.pki.goog/directory",
'google_test' => "https://dv.acme-v02.test-api.pki.goog/directory",
];
public static $no_inserttask = false;
private static $apiserver = "";

View File

@@ -146,6 +146,7 @@ class BackupCron extends FroxlorCron
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
// get all customer database-names
// @fixme respect multiple dbservers
$sel_stmt = Database::prepare("SELECT `databasename` FROM `" . TABLE_PANEL_DATABASES . "` WHERE `customerid` = :cid");
Database::pexecute($sel_stmt, [
'cid' => $data['customerid']

View File

@@ -127,7 +127,7 @@ class TrafficCron extends FroxlorCron
while ($row_database = $databases_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($last_dbserver != $row_database['dbserver']) {
Database::needRoot(true, $row_database['dbserver']);
Database::needRoot(true, $row_database['dbserver'], true);
$last_dbserver = $row_database['dbserver'];
$databases_list = [];

View File

@@ -28,6 +28,7 @@ namespace Froxlor\Database;
use Exception;
use Froxlor\FileDir;
use Froxlor\Froxlor;
use Froxlor\PhpHelper;
use Froxlor\Settings;
use Froxlor\UI\Panel\UI;
use PDO;
@@ -79,6 +80,8 @@ class Database
private static $sqldata = null;
private static $need_dbname = true;
/**
* Wrapper for PDOStatement::execute so we can catch the PDOException
* and display the error nicely on the panel - also fetches the
@@ -135,7 +138,7 @@ class Database
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
// le format
if (isset($sql['root_user']) && isset($sql['root_password']) && !is_array($sql_root)) {
if (isset($sql['root_user']) && isset($sql['root_password']) && empty($sql_root)) {
$sql_root = [
0 => [
'caption' => 'Default',
@@ -145,12 +148,20 @@ class Database
'password' => $sql['root_password']
]
];
unset($sql['root_user']);
unset($sql['root_password']);
// write new layout so this won't happen again
self::generateNewUserData($sql, $sql_root);
// re-read file
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
}
$substitutions = [
$sql['password'] => 'DB_UNPRIV_PWD',
$sql_root[0]['password'] => 'DB_ROOT_PWD'
];
foreach ($sql_root as $dbserver => $sql_root_data) {
$substitutions[$sql_root_data[$dbserver]]['password'] = 'DB_ROOT_PWD';
}
// hide username/password in messages
$error_message = $error->getMessage();
@@ -341,12 +352,13 @@ class Database
* @param int $dbserver
* optional
*/
public static function needRoot($needroot = false, $dbserver = 0)
public static function needRoot(bool $needroot = false, int $dbserver = 0, bool $need_db = true)
{
// force re-connecting to the db with corresponding user
// and set the $dbserver (mostly to 0 = default)
self::setServer($dbserver);
self::$needroot = $needroot;
self::$need_dbname = $need_db;
}
/**
@@ -405,7 +417,7 @@ class Database
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
// le format
if (self::$needroot == true && isset($sql['root_user']) && isset($sql['root_password']) && (!isset($sql_root) || !is_array($sql_root))) {
if (isset($sql['root_user']) && isset($sql['root_password']) && (!isset($sql_root) || !is_array($sql_root))) {
$sql_root = [
0 => [
'caption' => 'Default',
@@ -417,6 +429,10 @@ class Database
];
unset($sql['root_user']);
unset($sql['root_password']);
// write new layout so this won't happen again
self::generateNewUserData($sql, $sql_root);
// re-read file
require Froxlor::getInstallDir() . "/lib/userdata.inc.php";
}
// either root or unprivileged user
@@ -465,10 +481,11 @@ class Database
'ATTR_ERRMODE' => 'ERRMODE_EXCEPTION'
];
$dbconf["dsn"] = [
'dbname' => $sql["db"],
'charset' => 'utf8'
];
$dbconf["dsn"] = ['charset' => 'utf8'];
if (self::$need_dbname) {
$dbconf["dsn"]['dbname'] = $sql["db"];
}
if ($socket != null) {
$dbconf["dsn"]['unix_socket'] = FileDir::makeCorrectFile($socket);
@@ -578,4 +595,22 @@ class Database
}
return $result;
}
/**
* write new userdata.inc.php file
*/
private static function generateNewUserData(array $sql, array $sql_root)
{
$content = PhpHelper::parseArrayToPhpFile(
['sql' => $sql, 'sql_root' => $sql_root],
'automatically generated userdata.inc.php for froxlor'
);
chmod(Froxlor::getInstallDir() . "/lib/userdata.inc.php", 0700);
file_put_contents(Froxlor::getInstallDir() . "/lib/userdata.inc.php", $content);
chmod(Froxlor::getInstallDir() . "/lib/userdata.inc.php", 0400);
clearstatcache();
if (function_exists('opcache_invalidate')) {
@opcache_invalidate(Froxlor::getInstallDir() . "/lib/userdata.inc.php", true);
}
}
}

View File

@@ -96,7 +96,7 @@ class DbManager
$dbservers_stmt = Database::query("SELECT DISTINCT `dbserver` FROM `" . TABLE_PANEL_DATABASES . "`");
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver['dbserver']);
Database::needRoot(true, $dbserver['dbserver'], false);
$dbm = new DbManager(FroxlorLogger::getInstanceOf());
$users = $dbm->getManager()->getAllSqlUsers(false);
@@ -144,7 +144,7 @@ class DbManager
*/
public function createDatabase($loginname = null, $password = null, int $dbserver = 0, $last_accnumber = 0)
{
Database::needRoot(true, $dbserver);
Database::needRoot(true, $dbserver, false);
// check whether we shall create a random username
if (strtoupper(Settings::Get('customer.mysqlprefix')) == 'RANDOM') {
@@ -169,18 +169,17 @@ class DbManager
// now create the database itself
$this->getManager()->createDatabase($username);
$this->log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "created database '" . $username . "'");
// and give permission to the user on every access-host we have
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$this->getManager()->grantPrivilegesTo($username, $password, $mysql_access_host);
$this->log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "grant all privileges for '" . $username . "'@'" . $mysql_access_host . "'");
}
$this->getManager()->flushPrivileges();
Database::needRoot(false);
$this->log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "created database '" . $username . "'");
return $username;
}

View File

@@ -31,7 +31,7 @@ final class Froxlor
{
// Main version variable
const VERSION = '2.0.1';
const VERSION = '2.0.7';
// Database version (YYYYMMDDC where C is a daily counter)
const DBVERSION = '202212060';

View File

@@ -32,7 +32,7 @@ class Mysql
public static function dbserver(array $attributes): string
{
// get sql-root access data
Database::needRoot(true, (int)$attributes['data']);
Database::needRoot(true, (int)$attributes['data'], false);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);

View File

@@ -113,17 +113,15 @@ class Collection
public function withPagination(array $columns, array $default_sorting = []): Collection
{
// Get only searchable columns
/*
$sortableColumns = [];
foreach ($columns as $key => $column) {
if (isset($column['sortable']) && $column['sortable']) {
if (!isset($column['sortable']) || (isset($column['sortable']) && $column['sortable'])) {
$sortableColumns[$key] = $column;
}
}
*/
// Prepare pagination
$this->pagination = new Pagination($columns, $this->count(), (int)Settings::Get('panel.paging'), $default_sorting);
$this->pagination = new Pagination($sortableColumns, $this->count(), (int)Settings::Get('panel.paging'), $default_sorting);
$this->params = array_merge($this->params, $this->pagination->getApiCommandParams());
return $this;

View File

@@ -63,7 +63,9 @@ class Pagination
$this->perPage = $perPage;
$this->pageno = 1;
// add default limitation by settings
$this->addLimit(Settings::Get('panel.paging'));
if (Settings::Get('panel.paging') > 0) {
$this->addLimit(Settings::Get('panel.paging'));
}
// check search request
$this->searchtext = '';
if (count($fields) > 0) {
@@ -205,7 +207,7 @@ class Pagination
"total" => $this->entries,
"per_page" => $this->perPage,
"current_page" => $this->pageno,
"last_page" => ceil($this->entries / $this->perPage),
"last_page" => (Settings::Get('panel.paging') > 0) ? ceil($this->entries / $this->perPage) : -1,
"from" => $this->data['sql_offset'] ?? null,
"to" => min($this->data['sql_offset'] + $this->perPage, $this->entries),
'sortfields' => array_keys($this->fields),

View File

@@ -95,7 +95,7 @@ class UI
session_set_cookie_params([
'lifetime' => self::$install_mode ? 7200 : 600, // will be renewed based on settings in lib/init.php
'path' => '/',
'domain' => $_SERVER['HTTP_HOST'],
'domain' => $_SERVER['SERVER_NAME'],
'secure' => self::requestIsHttps(),
'httponly' => true,
'samesite' => 'Strict'
@@ -260,8 +260,17 @@ class UI
*/
public static function twigBuffer($name, array $context = [])
{
$template_file = self::getTheme() . '/' . $name;
if (!file_exists(Froxlor::getInstallDir() . '/templates/' . $template_file)) {
PhpHelper::phpErrHandler(E_USER_WARNING, "Template '" . $template_file . "' could not be found, trying fallback theme", __FILE__, __LINE__);
$template_file = self::$default_theme . '/'. $name;
if (!file_exists(Froxlor::getInstallDir() . '/templates/' . $template_file)) {
PhpHelper::phpErrHandler(E_USER_ERROR, "Unknown template '" . $template_file . "'", __FILE__, __LINE__);
}
}
self::$twigbuf[] = [
self::getTheme() . '/' . $name => $context
$template_file => $context
];
}

View File

@@ -4678,7 +4678,7 @@ aliases: files
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_configdir}}]]></command>
<command><![CDATA[mkdir -p {{settings.system.mod_fcgid_tmpdir}}]]></command>
<command><![CDATA[chmod 1777 {{settings.system.mod_fcgid_tmpdir}}]]></command>
<command><![CDATA[a2dismod php7.2]]></command>
<command><![CDATA[a2dismod php7.4]]></command>
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the
dirty work -->
@@ -4711,7 +4711,7 @@ aliases: files
</visibility>
<visibility mode="true">{{settings.phpfpm.enabled_ownvhost}}
</visibility>
<command><![CDATA[a2dismod php7.2]]></command>
<command><![CDATA[a2dismod php7.4]]></command>
</commands>
<!-- instead of just restarting apache, we let the cronjob do all the
dirty work -->

View File

@@ -33,10 +33,16 @@ return [
'value' => $result['databasename']
],
'mysql_server' => [
'visible' => count($mysql_servers) > 1,
'type' => 'hidden',
'value' => $result['dbserver'] ?? 0,
],
'mysql_server_info' => [
'visible' => count($mysql_servers) > 1,
'label' => lng('mysql.mysql_server'),
'type' => 'label',
'value' => $mysql_servers[$result['dbserver']] ?? 'unknown db server'
'disabled' => true,
'value' => $mysql_servers[$result['dbserver']] ?? 'unknown db server',
],
'description' => [
'label' => lng('mysql.databasedescription'),

View File

@@ -332,7 +332,7 @@ if (CurrentUser::hasSession()) {
$cookie_params = [
'expires' => time() + Settings::Get('session.sessiontimeout'),
'path' => '/',
'domain' => $_SERVER['HTTP_HOST'],
'domain' => $_SERVER['SERVER_NAME'],
'secure' => UI::requestIsHttps(),
'httponly' => true,
'samesite' => 'Strict'

View File

@@ -54,11 +54,13 @@ return [
'label' => lng('ssl_certificates.valid_from'),
'field' => 'validfromdate',
'searchable' => false,
'sortable' => false,
],
'c.validtodate' => [
'label' => lng('ssl_certificates.valid_until'),
'field' => 'validtodate',
'searchable' => false,
'sortable' => false,
],
],
'visible_columns' => Listing::getVisibleColumnsForListing('sslcertificates_list', [

36
package-lock.json generated
View File

@@ -5103,9 +5103,9 @@
}
},
"node_modules/img-loader/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -5437,9 +5437,9 @@
"dev": true
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@@ -8448,9 +8448,9 @@
}
},
"node_modules/vue-style-loader/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -12919,9 +12919,9 @@
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -13165,9 +13165,9 @@
"dev": true
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"jsonfile": {
@@ -15379,9 +15379,9 @@
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"

View File

@@ -197,7 +197,7 @@
{% if field.next_to is defined %}
<div class="input-group">
{% endif %}
<select {% if field.visible is defined and field.visible == false %} disabled {% endif %} class="form-select {% if field.valid is defined and field.valid == false %}is-invalid{% endif %}" name="{{ id }}{% if field.select_mode is defined and field.select_mode == 'multiple' %}[]{% endif %}" id="{{ id }}" {% if field.mandatory is defined and field.mandatory %} required {% endif %} {% if field.select_mode is defined and field.select_mode == 'multiple' %} multiple="multiple" {% endif %}>
<select {% if field.visible is defined and field.visible == false %} disabled {% endif %} class="form-select {% if field.valid is defined and field.valid == false %}is-invalid{% endif %}" name="{{ id }}{% if field.select_mode is defined and field.select_mode == 'multiple' %}[]{% endif %}" id="{{ id }}" {% if field.mandatory is defined and field.mandatory %} required {% endif %} {% if field.select_mode is defined and field.select_mode == 'multiple' %} multiple="multiple" {% endif %}{% if field.readonly is defined and field.readonly %} readonly {% endif %}>
{% for val,txt in field.select_var %}
<option value="{{ val }}" {% if field.selected is defined and ((field.selected is not iterable and field.selected == val) or (field.selected is iterable and val in field.selected|keys)) %} selected="selected" {% endif %}>{{ txt|raw }}</option>
{% endfor %}