From 31500522ce6bdd5548ce3e2e17c2dbdc99adb8ab Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 9 Aug 2022 15:49:44 +0200 Subject: [PATCH 01/11] make froxlor_master_cronkjob a froxlor-cli command; secure files/folders in froxlor-virtualhost; Signed-off-by: Michael Kaufmann --- actions/admin/settings/125.cronjob.php | 8 - bin/froxlor-cli | 2 + install/updates/froxlor/update_0.11.inc.php | 7 +- install/updatesql.php | 6 +- lib/Froxlor/Cli/CliCommand.php | 38 +- lib/Froxlor/Cli/ConfigServices.php | 2 +- lib/Froxlor/Cli/MasterCron.php | 258 +++++++++++++ lib/Froxlor/Cron/CronConfig.php | 4 +- lib/Froxlor/Cron/FroxlorCron.php | 5 + lib/Froxlor/Cron/Http/Apache.php | 22 ++ lib/Froxlor/Cron/Http/Lighttpd.php | 9 + lib/Froxlor/Cron/Http/Nginx.php | 30 +- lib/Froxlor/Cron/MasterCron.php | 392 -------------------- lib/Froxlor/FroxlorLogger.php | 22 +- lib/Froxlor/UI/Linker.php | 2 +- lib/configfiles/bionic.xml | 6 +- lib/configfiles/bullseye.xml | 6 +- lib/configfiles/buster.xml | 6 +- lib/configfiles/focal.xml | 6 +- lib/configfiles/gentoo.xml | 6 +- lib/init.php | 16 +- lng/de.lng.php | 6 - lng/en.lng.php | 6 - scripts/froxlor_master_cronjob.php | 34 -- scripts/index.html | 0 25 files changed, 398 insertions(+), 501 deletions(-) create mode 100644 lib/Froxlor/Cli/MasterCron.php delete mode 100644 lib/Froxlor/Cron/MasterCron.php delete mode 100644 scripts/froxlor_master_cronjob.php delete mode 100644 scripts/index.html diff --git a/actions/admin/settings/125.cronjob.php b/actions/admin/settings/125.cronjob.php index 383c0d19..99291c59 100644 --- a/actions/admin/settings/125.cronjob.php +++ b/actions/admin/settings/125.cronjob.php @@ -62,14 +62,6 @@ return [ 'type' => 'checkbox', 'default' => false, 'save_method' => 'storeSettingField' - ], - 'system_debug_cron' => [ - 'label' => lng('serversettings.cron.debug'), - 'settinggroup' => 'system', - 'varname' => 'debug_cron', - 'type' => 'checkbox', - 'default' => false, - 'save_method' => 'storeSettingField' ] ] ] diff --git a/bin/froxlor-cli b/bin/froxlor-cli index b6a62b4b..26bdc2b7 100755 --- a/bin/froxlor-cli +++ b/bin/froxlor-cli @@ -33,6 +33,7 @@ use Froxlor\Cli\PhpSessionclean; use Froxlor\Cli\SwitchServerIp; use Froxlor\Cli\UpdateCommand; use Froxlor\Cli\InstallCommand; +use Froxlor\Cli\MasterCron; use Froxlor\Froxlor; // validate correct php version @@ -55,4 +56,5 @@ $application->add(new PhpSessionclean()); $application->add(new SwitchServerIp()); $application->add(new UpdateCommand()); $application->add(new InstallCommand()); +$application->add(new MasterCron()); $application->run(); diff --git a/install/updates/froxlor/update_0.11.inc.php b/install/updates/froxlor/update_0.11.inc.php index 5177e26b..d4454423 100644 --- a/install/updates/froxlor/update_0.11.inc.php +++ b/install/updates/froxlor/update_0.11.inc.php @@ -24,6 +24,7 @@ */ use Froxlor\Froxlor; +use Froxlor\FileDir; use Froxlor\Database\Database; use Froxlor\Settings; use Froxlor\Install\Update; @@ -105,15 +106,16 @@ if (Froxlor::isFroxlorVersion('0.10.99')) { "lng/lng_references.php", "lng/portugues.lng.php", "lng/swedish.lng.php", + "scripts", ); $disabled = explode(',', ini_get('disable_functions')); $exec_allowed = !in_array('exec', $disabled); $del_list = ""; foreach ($to_clean as $filedir) { - $complete_filedir = \Froxlor\Froxlor::getInstallDir() . $filedir; + $complete_filedir = Froxlor::getInstallDir() . $filedir; if (file_exists($complete_filedir)) { if ($exec_allowed) { - Froxlor\FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir)); + FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir)); } else { $del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL; } @@ -154,6 +156,7 @@ if (Froxlor::isFroxlorVersion('0.10.99')) { 'Česká republika' => 'cs' ]; Settings::Set('panel.standardlanguage', $lang_map[Settings::Get('panel_standardlanguage')] ?? 'en'); + Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'system' AND `varname` = 'debug_cron'"); Update::lastStepStatus(0); Froxlor::updateToVersion($update_to); diff --git a/install/updatesql.php b/install/updatesql.php index e0c90fd5..d7e5ae56 100644 --- a/install/updatesql.php +++ b/install/updatesql.php @@ -64,10 +64,10 @@ if (Froxlor::isFroxlor()) { $integrity = new IntegrityCheck(); if (!$integrity->checkAll()) { - Update::lastStepStatus(1, 'Monkeys ate the integrity'); - Update::showUpdateStep("Trying to remove monkeys, feeding bananas"); + Update::lastStepStatus(1, 'Integrity could not be validated'); + Update::showUpdateStep("Trying to automatically restore integrity"); if (!$integrity->fixAll()) { - Update::lastStepStatus(2, 'failed', 'Some monkeys just would not move, you should contact team@froxlor.org'); + Update::lastStepStatus(2, 'failed', 'Check "database validation" as admin on the left-side menu to see where the problem is'); } else { Update::lastStepStatus(0, 'Integrity restored'); } diff --git a/lib/Froxlor/Cli/CliCommand.php b/lib/Froxlor/Cli/CliCommand.php index 935c41e6..36c29223 100644 --- a/lib/Froxlor/Cli/CliCommand.php +++ b/lib/Froxlor/Cli/CliCommand.php @@ -25,7 +25,9 @@ namespace Froxlor\Cli; +use Exception; use Froxlor\Froxlor; +use Froxlor\Settings; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -39,10 +41,42 @@ class CliCommand extends Command $output->writeln("Could not find froxlor's userdata.inc.php file. You should use this script only with an installed froxlor system."); return self::INVALID; } - if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) { - $output->writeln("It seems that the froxlor files have been updated. Please login and finish the update procedure."); + // try database connection + try { + Database::query("SELECT 1"); + } catch (Exception $e) { + // Do not proceed further if no database connection could be established + $output->writeln("" . $e->getMessage() . ""); return self::INVALID; } + if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) { + if ((int)Settings::Get('system.cron_allowautoupdate') == 1) { + return $this->runUpdate($output); + } else { + $output->writeln("It seems that the froxlor files have been updated. Please login and finish the update procedure."); + return self::INVALID; + } + } return self::SUCCESS; } + + private function runUpdate(OutputInterface $output): int + { + $output->writeln('Automatic update is activated and we are going to proceed without any notices'); + include_once Froxlor::getInstallDir() . '/lib/tables.inc.php'; + define('_CRON_UPDATE', 1); + ob_start([ + 'this', + 'cleanUpdateOutput' + ]); + include_once Froxlor::getInstallDir() . '/install/updatesql.php'; + ob_end_flush(); + $output->writeln('Automatic update done - you should check your settings to be sure everything is fine'); + return self::SUCCCESS; + } + + private function cleanUpdateOutput($buffer) + { + return strip_tags(preg_replace("//", "\n", $buffer)); + } } diff --git a/lib/Froxlor/Cli/ConfigServices.php b/lib/Froxlor/Cli/ConfigServices.php index 07902d0c..ed4bb272 100644 --- a/lib/Froxlor/Cli/ConfigServices.php +++ b/lib/Froxlor/Cli/ConfigServices.php @@ -410,7 +410,7 @@ final class ConfigServices extends CliCommand // set is_configured flag Settings::Set('panel.is_configured', '1', true); // run cronjob at the end to ensure configs are all up to date - exec('php ' . Froxlor::getInstallDir() . 'scripts/froxlor_master_cronjob.php --force'); + exec('php ' . Froxlor::getInstallDir() . 'bin/froxlor-cli froxlor:cron --force'); // and done $output->writeln('All services have been configured'); return self::SUCCESS; diff --git a/lib/Froxlor/Cli/MasterCron.php b/lib/Froxlor/Cli/MasterCron.php new file mode 100644 index 00000000..c2c8a0ff --- /dev/null +++ b/lib/Froxlor/Cli/MasterCron.php @@ -0,0 +1,258 @@ + + * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 + */ + +namespace Froxlor\Cli; + +use Froxlor\Froxlor; +use Froxlor\FileDir; +use Froxlor\Settings; +use Froxlor\FroxlorLogger; +use Froxlor\Database\Database; +use Froxlor\System\Cronjob; +use Froxlor\Cron\TaskId; +use Froxlor\Cron\System\Extrausers; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Output\OutputInterface; + +final class MasterCron extends CliCommand +{ + private $lockFile = null; + + private $cronLog = null; + + protected function configure() + { + $this->setName('froxlor:cron'); + $this->setDescription('Regulary perform tasks created by froxlor'); + $this->addArgument('job', InputArgument::IS_ARRAY, 'Job(s) to run'); + $this->addOption('run-task', 'r', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Run a specific task [1 = re-generate configs, 4 = re-generate dns zones, 10 = re-set quotas, 99 = re-create cron.d-file]') + ->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces re-generating of config-files (webserver, nameserver, etc.)') + ->addOption('debug', 'd', InputOption::VALUE_NONE, 'Output debug information about what is going on to STDOUT.') + ->addOption('no-fork', 'N', InputOption::VALUE_NONE, 'Do not fork to background (traffic cron only).'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $result = self::SUCCESS; + $result = $this->validateRequirements($input, $output); + + $jobs = $input->getArgument('job'); + + // handle force option + if ($input->getOption('force')) { + // rebuild all config files + Cronjob::inserttask(TaskId::REBUILD_VHOST); + Cronjob::inserttask(TaskId::REBUILD_DNS); + Cronjob::inserttask(TaskId::CREATE_QUOTA); + Cronjob::inserttask(TaskId::REBUILD_CRON); + array_push($jobs, 'tasks'); + define('CRON_IS_FORCED', 1); + } + // handle debug option + if ($input->getOption('debug')) { + define('CRON_DEBUG_FLAG', 1); + } + // handle no-fork option + if ($input->getOption('no-fork')) { + define('CRON_NOFORK_FLAG', 1); + } + // handle run-task option + if ($input->getOption('run-task')) { + $tasks_to_run = $input->getOption('run-task'); + foreach ($tasks_to_run as $ttr) { + if (in_array($ttr, [1, 4, 10, 99])) { + Cronjob::inserttask($ttr); + array_push($jobs, 'tasks'); + } else { + $output->writeln('Unknown task number "' . $ttr . '"'); + } + } + } + + // unique job-array + $jobs = array_unique($jobs); + + // check for given job(s) to execute and return if empty + if (empty($jobs)) { + $output->writeln('No job given. Nothing to do.'); + return self::INVALID; + } + + $this->validateOwnership($output); + + $this->cronLog = FroxlorLogger::getInstanceOf([ + 'loginname' => 'cronjob' + ]); + $this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG')); + + // check whether there are actual tasks to perform by 'tasks'-cron so + // we dont regenerate files unnecessarily + $tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`"); + $tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC); + + // iterate through all needed jobs + foreach ($jobs as $job) { + // lock the job + if ($this->lockJob($job, $output)) { + // get FQDN of cron-class + $cronfile = $this->getCronModule($job, $output); + // validate + if ($cronfile && class_exists($cronfile)) { + // info + $output->writeln('Running "' . $job . '" job' . (defined('CRON_IS_FORCED') ? ' (forced)' : '') . (defined('CRON_DEBUG_FLAG') ? ' (debug)' : '') . (defined('CRON_NOFORK_FLAG') ? ' (not forking)' : '') . ''); + // update time of last run + Cronjob::updateLastRunOfCron($job); + // set logger + $cronfile::setCronlog($this->cronLog); + // run the job + $cronfile::run(); + } + // free the lockfile + $this->unlockJob($job); + } + } + + // regenerate nss-extrausers files / invalidate nscd cache (if used) + $this->refreshUsers((int) $tasks_cnt['jobcnt']); + + // we have to check the system's last guid with every cron run + // in case the admin installed new software which added a new user + //so users in the database don't conflict with system users + $this->cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Checking system\'s last guid'); + Cronjob::checkLastGuid(); + + // check for cron.d-generation task and create it if necessary + CronConfig::checkCrondConfigurationFile(); + + // reset cronlog-flag if set to "once" + if ((int) Settings::Get('logger.log_cron') == 1) { + FroxlorLogger::getInstanceOf()->setCronLog(0); + } + + return $result; + } + + private function refreshUsers(int $jobcount = 0) + { + if ($jobcount > 0) { + if (Settings::Get('system.nssextrausers') == 1) { + Extrausers::generateFiles(self::$cronlog); + return; + } + + // clear NSCD cache if using fcgid or fpm, #1570 - not needed for nss-extrausers + if ((Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) && Settings::Get('system.nssextrausers') == 0) { + $false_val = false; + FileDir::safe_exec('nscd -i passwd 1> /dev/null', $false_val, [ + '>' + ]); + FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, [ + '>' + ]); + } + } + } + + private function validateOwnership(OutputInterface $output) + { + // when using fcgid or fpm for froxlor-vhost itself, we have to check + // whether the permission of the files are still correct + $output->write('Checking froxlor file permissions...'); + $_mypath = FileDir::makeCorrectDir(Froxlor::getInstallDir()); + + if (((int)Settings::Get('system.mod_fcgid') == 1 && (int)Settings::Get('system.mod_fcgid_ownvhost') == 1) || ((int)Settings::Get('phpfpm.enabled') == 1 && (int)Settings::Get('phpfpm.enabled_ownvhost') == 1)) { + $user = Settings::Get('system.mod_fcgid_httpuser'); + $group = Settings::Get('system.mod_fcgid_httpgroup'); + + if (Settings::Get('phpfpm.enabled') == 1) { + $user = Settings::Get('phpfpm.vhost_httpuser'); + $group = Settings::Get('phpfpm.vhost_httpgroup'); + } + // all the files and folders have to belong to the local user + FileDir::safe_exec('chown -R ' . $user . ':' . $group . ' ' . escapeshellarg($_mypath)); + } else { + // back to webserver permission + $user = Settings::Get('system.httpuser'); + $group = Settings::Get('system.httpgroup'); + FileDir::safe_exec('chown -R ' . $user . ':' . $group . ' ' . escapeshellarg($_mypath)); + } + $output->writeln('OK'); + } + + private function getCronModule(string $cronname, OutputInterface $output) + { + $upd_stmt = Database::prepare(" + SELECT `cronclass` FROM `" . TABLE_PANEL_CRONRUNS . "` WHERE `cronfile` = :cron; + "); + $cron = Database::pexecute_first($upd_stmt, [ + 'cron' => $cronname + ]); + if ($cron) { + return $cron['cronclass']; + } + $output->writeln("Requested cronjob '" . $cronname . "' could not be found."); + return false; + } + + private function lockJob(string $job, OutputInterface $output): bool + { + + $this->lockFile = '/run/lock/froxlor_' . $job . '.lock'; + + if (file_exists($this->lockFile)) { + $jobinfo = json_decode(file_get_contents($this->lockFile), true); + $check_pid_return = null; + // get status of process + system("kill -CHLD " . (int)$jobinfo['pid'] . " 1> /dev/null 2> /dev/null", $check_pid_return); + if ($check_pid_return == 1) { + // Process does not seem to run, most likely it has died + $this->unlockJob($job); + } else { + // cronjob still running, output info and stop + $output->writeln([ + 'Job "' . $jobinfo['job'] . '" is currently running.', + 'Started: ' . date('d.m.Y H:i', (int) $jobinfo['startts']), + 'PID: ' . $jobinfo['pid'] . '' + ]); + return false; + } + } + + $jobinfo = [ + 'job' => $job, + 'startts' => time(), + 'pid' => getmypid() + ]; + file_put_contents($this->lockFile, json_encode($jobinfo)); + return true; + } + + private function unlockJob(string $job): bool + { + return @unlink($this->lockFile); + } +} diff --git a/lib/Froxlor/Cron/CronConfig.php b/lib/Froxlor/Cron/CronConfig.php index 1f7ff2d1..4be56929 100644 --- a/lib/Froxlor/Cron/CronConfig.php +++ b/lib/Froxlor/Cron/CronConfig.php @@ -110,7 +110,7 @@ class CronConfig } // create entry-line - $cronfile .= "root " . $binpath . " " . FileDir::makeCorrectFile(Froxlor::getInstallDir() . "/scripts/froxlor_master_cronjob.php") . " --" . $row_cronentry['cronfile'] . " 1> /dev/null\n"; + $cronfile .= "root " . $binpath . " " . FileDir::makeCorrectFile(Froxlor::getInstallDir() . "/bin/froxlor-cli") . " froxlor:cron " . escapeshellarg($row_cronentry['cronfile']) . " -q 1> /dev/null\n"; } } @@ -135,7 +135,7 @@ class CronConfig $newcrontab = ""; foreach ($crontablines as $ctl) { $ctl = trim($ctl); - if (!empty($ctl) && !preg_match("/(.*)froxlor_master_cronjob\.php(.*)/", $ctl)) { + if (!empty($ctl) && !preg_match("/(.*)froxlor\:cron(.*)/", $ctl)) { $newcrontab .= $ctl . "\n"; } } diff --git a/lib/Froxlor/Cron/FroxlorCron.php b/lib/Froxlor/Cron/FroxlorCron.php index 3ac2ab0a..7e5b4097 100644 --- a/lib/Froxlor/Cron/FroxlorCron.php +++ b/lib/Froxlor/Cron/FroxlorCron.php @@ -42,4 +42,9 @@ abstract class FroxlorCron { static::$lockfile = $lockfile; } + + public static function setCronlog($cronlog = null) + { + static::$cronlog = $cronlog; + } } diff --git a/lib/Froxlor/Cron/Http/Apache.php b/lib/Froxlor/Cron/Http/Apache.php index b3e1e264..ad79ed88 100644 --- a/lib/Froxlor/Cron/Http/Apache.php +++ b/lib/Froxlor/Cron/Http/Apache.php @@ -25,6 +25,7 @@ namespace Froxlor\Cron\Http; +use Froxlor\Froxlor; use Froxlor\Cron\Http\Php\PhpInterface; use Froxlor\Customer\Customer; use Froxlor\Database\Database; @@ -161,6 +162,27 @@ class Apache extends HttpConfigBase } if (!$is_redirect) { + // protect lib/userdata.inc.php + $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; + $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; + if (Settings::Get('system.apache24') == '1') { + $this->virtualhosts_data[$vhosts_filename] .= ' Require all denied' . "\n"; + } else { + $this->virtualhosts_data[$vhosts_filename] .= ' Order deny,allow' . "\n"; + $this->virtualhosts_data[$vhosts_filename] .= ' deny from all' . "\n"; + } + $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; + $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; + // protect bin/ + $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; + if (Settings::Get('system.apache24') == '1') { + $this->virtualhosts_data[$vhosts_filename] .= ' Require all denied' . "\n"; + } else { + $this->virtualhosts_data[$vhosts_filename] .= ' Order deny,allow' . "\n"; + $this->virtualhosts_data[$vhosts_filename] .= ' deny from all' . "\n"; + } + $this->virtualhosts_data[$vhosts_filename] .= ' ' . "\n"; + // create fcgid -Part (starter is created in apache_fcgid) if (Settings::Get('system.mod_fcgid_ownvhost') == '1' && Settings::Get('system.mod_fcgid') == '1') { $configdir = FileDir::makeCorrectDir(Settings::Get('system.mod_fcgid_configdir') . '/froxlor.panel/' . Settings::Get('system.hostname')); diff --git a/lib/Froxlor/Cron/Http/Lighttpd.php b/lib/Froxlor/Cron/Http/Lighttpd.php index 3e0ac959..660113cd 100644 --- a/lib/Froxlor/Cron/Http/Lighttpd.php +++ b/lib/Froxlor/Cron/Http/Lighttpd.php @@ -125,6 +125,15 @@ class Lighttpd extends HttpConfigBase } if (!$is_redirect) { + // protect lib/userdata.inc.php + $this->lighttpd_data[$vhosts_filename] .= ' $HTTP["host"] =~ "' . rtrim(Froxlor::getInstallDir(), "/") . '/lib" {' . "\n"; + $this->lighttpd_data[$vhosts_filename] .= ' url.access-deny = ("userdata.inc.php")' . "\n"; + $this->lighttpd_data[$vhosts_filename] .= ' }' . "\n"; + // protect bin/ + $this->lighttpd_data[$vhosts_filename] .= ' $HTTP["host"] =~ "' . rtrim(Froxlor::getInstallDir(), "/") . '/bin" {' . "\n"; + $this->lighttpd_data[$vhosts_filename] .= ' url.access-deny = ("")' . "\n"; + $this->lighttpd_data[$vhosts_filename] .= ' }' . "\n"; + /** * dirprotection, see #72 * diff --git a/lib/Froxlor/Cron/Http/Nginx.php b/lib/Froxlor/Cron/Http/Nginx.php index b5b7d05d..a0c9c1bb 100644 --- a/lib/Froxlor/Cron/Http/Nginx.php +++ b/lib/Froxlor/Cron/Http/Nginx.php @@ -218,15 +218,25 @@ class Nginx extends HttpConfigBase $this->nginx_data[$vhost_filename] .= "\t" . 'index index.php index.html index.htm;' . "\n\n"; $this->nginx_data[$vhost_filename] .= "\t" . 'location / {' . "\n"; $this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n"; + + // protect lib/userdata.inc.php + $this->nginx_data[$vhosts_filename] .= "\t" . 'location = ' . rtrim(Froxlor::getInstallDir(), "/") . '/lib/userdata.inc.php {' . "\n"; + $this->nginx_data[$vhosts_filename] .= "\t" . ' deny all;' . "\n"; + $this->nginx_data[$vhosts_filename] .= "\t" . '}' . "\n"; + + // protect bin/ + $this->nginx_data[$vhosts_filename] .= "\t" . 'location = ' . rtrim(Froxlor::getInstallDir(), "/") . '/bin {' . "\n"; + $this->nginx_data[$vhosts_filename] .= "\t" . ' deny all;' . "\n"; + $this->nginx_data[$vhosts_filename] .= "\t" . '}' . "\n"; } if ($row_ipsandports['specialsettings'] != '' && ($row_ipsandports['ssl'] == '0' || ($row_ipsandports['ssl'] == '1' && Settings::Get('system.use_ssl') == '1' && $row_ipsandports['include_specialsettings'] == '1'))) { $this->nginx_data[$vhost_filename] .= $this->processSpecialConfigTemplate($row_ipsandports['specialsettings'], [ - 'domain' => Settings::Get('system.hostname'), - 'loginname' => Settings::Get('phpfpm.vhost_httpuser'), - 'documentroot' => $mypath, - 'customerroot' => $mypath - ], $row_ipsandports['ip'], $row_ipsandports['port'], $row_ipsandports['ssl'] == '1') . "\n"; + 'domain' => Settings::Get('system.hostname'), + 'loginname' => Settings::Get('phpfpm.vhost_httpuser'), + 'documentroot' => $mypath, + 'customerroot' => $mypath + ], $row_ipsandports['ip'], $row_ipsandports['port'], $row_ipsandports['ssl'] == '1') . "\n"; } /** @@ -239,11 +249,11 @@ class Nginx extends HttpConfigBase $this->nginx_data[$vhost_filename] .= $this->composeSslSettings($row_ipsandports); if ($row_ipsandports['ssl_specialsettings'] != '') { $this->nginx_data[$vhost_filename] .= $this->processSpecialConfigTemplate($row_ipsandports['ssl_specialsettings'], [ - 'domain' => Settings::Get('system.hostname'), - 'loginname' => Settings::Get('phpfpm.vhost_httpuser'), - 'documentroot' => $mypath, - 'customerroot' => $mypath - ], $row_ipsandports['ip'], $row_ipsandports['port'], $row_ipsandports['ssl'] == '1') . "\n"; + 'domain' => Settings::Get('system.hostname'), + 'loginname' => Settings::Get('phpfpm.vhost_httpuser'), + 'documentroot' => $mypath, + 'customerroot' => $mypath + ], $row_ipsandports['ip'], $row_ipsandports['port'], $row_ipsandports['ssl'] == '1') . "\n"; } } diff --git a/lib/Froxlor/Cron/MasterCron.php b/lib/Froxlor/Cron/MasterCron.php deleted file mode 100644 index f58f3be6..00000000 --- a/lib/Froxlor/Cron/MasterCron.php +++ /dev/null @@ -1,392 +0,0 @@ - - * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 - */ - -namespace Froxlor\Cron; - -use Exception; -use Froxlor\Cron\System\Extrausers; -use Froxlor\Database\Database; -use Froxlor\FileDir; -use Froxlor\Froxlor; -use Froxlor\FroxlorLogger; -use Froxlor\Settings; -use Froxlor\System\Cronjob; -use PDO; - -class MasterCron extends FroxlorCron -{ - - private static $argv = null; - - private static $debugHandler = null; - - private static $noncron_params = [ - 'force', - 'debug', - 'no-fork', - 'run-task' - ]; - - public static function setArguments($argv = null) - { - self::$argv = $argv; - } - - public static function run() - { - self::init(); - - $jobs_to_run = []; - - $argv = self::$argv; - /** - * check for --help - */ - if (count($argv) < 2 || (isset($argv[1]) && strtolower($argv[1]) == '--help')) { - echo "\n*** Froxlor Master Cronjob ***\n\n"; - echo "Below are possible parameters for this file\n\n"; - echo "--[cronname]\t\tincludes the given cron-file\n"; - echo "--force\t\t\tforces re-generating of config-files (webserver, nameserver, etc.)\n"; - echo "--run-task\t\trun a specific task [1 = re-generate configs, 4 = re-generate dns zones, 10 = re-set quotas, 99 = re-create cron.d-file]\n"; - echo "--debug\t\t\toutput debug information about what is going on to STDOUT.\n"; - echo "--no-fork\t\tdo not fork to backkground (traffic cron only).\n\n"; - exit(); - } - - /** - * check for parameters - * - * --[cronname] include [cronname] - * --force to include cron_tasks even if it's not its turn - * --debug to output debug information - */ - for ($x = 1; $x < count($argv); $x++) { - // check argument - if (isset($argv[$x])) { - // --force - if (strtolower($argv[$x]) == '--force') { - // really force re-generating of config-files by - // inserting task 1 - Cronjob::inserttask(TaskId::REBUILD_VHOST); - // bind (if enabled, \Froxlor\System\Cronjob::inserttask() checks this) - Cronjob::inserttask(TaskId::REBUILD_DNS); - // set quotas (if enabled) - Cronjob::inserttask(TaskId::CREATE_QUOTA); - // also regenerate cron.d-file - Cronjob::inserttask(TaskId::REBUILD_CRON); - array_push($jobs_to_run, 'tasks'); - define('CRON_IS_FORCED', 1); - } elseif (strtolower($argv[$x]) == '--debug') { - define('CRON_DEBUG_FLAG', 1); - } elseif (strtolower($argv[$x]) == '--no-fork') { - define('CRON_NOFORK_FLAG', 1); - } elseif (strtolower($argv[$x]) == '--run-task') { - if (isset($argv[$x + 1]) && in_array($argv[$x + 1], [1, 4, 10, 99])) { - Cronjob::inserttask($argv[$x + 1]); - array_push($jobs_to_run, 'tasks'); - } else { - echo "Invalid argument for --run-task\n"; - exit; - } - } elseif (substr(strtolower($argv[$x]), 0, 2) == '--') { - // --[cronname] - if (strlen($argv[$x]) > 3) { - $cronname = substr(strtolower($argv[$x]), 2); - array_push($jobs_to_run, $cronname); - } - } - } - } - - $jobs_to_run = array_unique($jobs_to_run); - - self::$cronlog->setCronDebugFlag(defined('CRON_DEBUG_FLAG')); - - $tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`"); - $tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC); - - // do we have anything to include? - if (count($jobs_to_run) > 0) { - // include all jobs we want to execute - foreach ($jobs_to_run as $cron) { - Cronjob::updateLastRunOfCron($cron); - $cronfile = self::getCronModule($cron); - if ($cronfile && class_exists($cronfile)) { - $cronfile::run(); - } - } - self::refreshUsers($tasks_cnt['jobcnt']); - } - - /** - * we have to check the system's last guid with every cron run - * in case the admin installed new software which added a new user - * so users in the database don't conflict with system users - */ - self::$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Checking system\'s last guid'); - Cronjob::checkLastGuid(); - - // shutdown cron - self::shutdown(); - } - - private static function init() - { - if (@php_sapi_name() != 'cli' && @php_sapi_name() != 'cgi' && @php_sapi_name() != 'cgi-fcgi') { - die('This script will only work in the shell.'); - } - - // ensure that default timezone is set - if (function_exists("date_default_timezone_set") && function_exists("date_default_timezone_get")) { - @date_default_timezone_set(@date_default_timezone_get()); - } - - $basename = basename($_SERVER['PHP_SELF'], '.php'); - $crontype = ""; - if (isset(self::$argv) && is_array(self::$argv) && count(self::$argv) > 1) { - for ($x = 1; $x < count(self::$argv); $x++) { - if (substr(self::$argv[$x], 0, 2) == '--' && strlen(self::$argv[$x]) > 3 && !in_array(substr(strtolower(self::$argv[$x]), 2), self::$noncron_params)) { - $crontype = substr(strtolower(self::$argv[$x]), 2); - $basename .= "-" . $crontype; - break; - } - } - } - $lockdir = '/var/run/'; - $lockFilename = 'froxlor_' . $basename . '.lock-'; - $lockfName = $lockFilename . getmypid(); - $lockfile = $lockdir . $lockfName; - self::setLockfile($lockfile); - - // create and open the lockfile! - self::$debugHandler = fopen($lockfile, 'w'); - fwrite(self::$debugHandler, 'Setting Lockfile to ' . $lockfile . "\n"); - fwrite(self::$debugHandler, 'Setting Froxlor installation path to ' . Froxlor::getInstallDir() . "\n"); - - if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) { - die("Froxlor does not seem to be installed yet - skipping cronjob"); - } - - $sql = []; - $sql_root = []; - // Includes the Usersettings eg. MySQL-Username/Passwort etc. - require Froxlor::getInstallDir() . '/lib/userdata.inc.php'; - fwrite(self::$debugHandler, 'Userdatas included' . "\n"); - - // Legacy sql-root-information - if (isset($sql['root_user']) && isset($sql['root_password']) && (!isset($sql_root) || !is_array($sql_root))) { - $sql_root = [ - 0 => [ - 'caption' => 'Default', - 'host' => $sql['host'], - 'user' => $sql['root_user'], - 'password' => $sql['root_password'] - ] - ]; - unset($sql['root_user']); - unset($sql['root_password']); - } - - require Froxlor::getInstallDir() . '/lib/functions.php'; - // Includes the MySQL-Tabledefinitions etc. - require Froxlor::getInstallDir() . '/lib/tables.inc.php'; - fwrite(self::$debugHandler, 'Table definitions included' . "\n"); - - // try database connection, it will throw - // and exception itself if failed - try { - Database::query("SELECT 1"); - } catch (Exception $e) { - // Do not proceed further if no database connection could be established - fclose(self::$debugHandler); - unlink($lockfile); - die($e->getMessage()); - } - - fwrite(self::$debugHandler, 'Database-connection established' . "\n"); - - // open the lockfile directory and scan for existing lockfiles - $lockDirHandle = opendir($lockdir); - - while ($fName = readdir($lockDirHandle)) { - if ($lockFilename == substr($fName, 0, strlen($lockFilename)) && $lockfName != $fName) { - // Check if last run jailed out with an exception - $croncontent = file($lockdir . $fName); - $lastline = $croncontent[(count($croncontent) - 1)]; - - if ($lastline == '=== Keep lockfile because of exception ===') { - fclose(self::$debugHandler); - unlink($lockfile); - Cronjob::dieWithMail('Last cron jailed out with an exception. Exiting...' . "\n" . 'Take a look into the contents of ' . $lockdir . $fName . '* for more information!' . "\n"); - } - - // Check if cron is running or has died. - $check_pid = substr(strrchr($fName, "-"), 1); - $check_pid_return = null; - system("kill -CHLD " . (int)$check_pid . " 1> /dev/null 2> /dev/null", $check_pid_return); - - if ($check_pid_return == 1) { - // Result: Existing lockfile/pid isn't running - // Most likely it has died - // - // Action: Remove it and continue - // - fwrite(self::$debugHandler, 'Previous cronjob didn\'t exit clean. PID: ' . $check_pid . "\n"); - fwrite(self::$debugHandler, 'Removing lockfile: ' . $lockdir . $fName . "\n"); - @unlink($lockdir . $fName); - } else { - // Result: A Cronscript with this pid - // is still running - // Action: remove my own Lock and die - // - // close the current lockfile - fclose(self::$debugHandler); - - // ... and delete it - unlink($lockfile); - Cronjob::dieWithMail('There is already a Cronjob for ' . $crontype . ' in progress. Exiting...' . "\n" . 'Take a look into the contents of ' . $lockdir . $lockFilename . '* for more information!' . "\n"); - } - } - } - - /** - * if using fcgid or fpm for froxlor-vhost itself, we have to check - * whether the permission of the files are still correct - */ - fwrite(self::$debugHandler, 'Checking froxlor file permissions' . "\n"); - $_mypath = FileDir::makeCorrectDir(Froxlor::getInstallDir()); - - if (((int)Settings::Get('system.mod_fcgid') == 1 && (int)Settings::Get('system.mod_fcgid_ownvhost') == 1) || ((int)Settings::Get('phpfpm.enabled') == 1 && (int)Settings::Get('phpfpm.enabled_ownvhost') == 1)) { - $user = Settings::Get('system.mod_fcgid_httpuser'); - $group = Settings::Get('system.mod_fcgid_httpgroup'); - - if (Settings::Get('phpfpm.enabled') == 1) { - $user = Settings::Get('phpfpm.vhost_httpuser'); - $group = Settings::Get('phpfpm.vhost_httpgroup'); - } - // all the files and folders have to belong to the local user - // now because we also use fcgid for our own vhost - FileDir::safe_exec('chown -R ' . $user . ':' . $group . ' ' . escapeshellarg($_mypath)); - } else { - // back to webserver permission - $user = Settings::Get('system.httpuser'); - $group = Settings::Get('system.httpgroup'); - FileDir::safe_exec('chown -R ' . $user . ':' . $group . ' ' . escapeshellarg($_mypath)); - } - - // Initialize logging - self::$cronlog = FroxlorLogger::getInstanceOf([ - 'loginname' => 'cronjob' - ]); - fwrite(self::$debugHandler, 'Logger has been included' . "\n"); - - if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) { - if (Settings::Get('system.cron_allowautoupdate') == null || Settings::Get('system.cron_allowautoupdate') == 0) { - /** - * Do not proceed further if the Database version is not the same as the script version - */ - fclose(self::$debugHandler); - unlink($lockfile); - $errormessage = "Version of file doesn't match version of database. Exiting...\n\n"; - $errormessage .= "Possible reason: Froxlor update\n"; - $errormessage .= "Information: Current version in database: " . Settings::Get('panel.version') . (!empty(Froxlor::BRANDING) ? "-" . Froxlor::BRANDING : "") . " (DB: " . Settings::Get('panel.db_version') . ") - version of Froxlor files: " . Froxlor::getVersionString() . ")\n"; - $errormessage .= "Solution: Please visit your Foxlor admin interface for further information.\n"; - Cronjob::dieWithMail($errormessage); - } - - if (Settings::Get('system.cron_allowautoupdate') == 1) { - /** - * let's walk the walk - do the dangerous shit - */ - self::$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, 'Automatic update is activated and we are going to proceed without any notices'); - self::$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, 'all new settings etc. will be stored with the default value, that might not always be right for your system!'); - self::$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "If you don't want this to happen in the future consider removing the --allow-autoupdate flag from the cronjob"); - fwrite(self::$debugHandler, '*** WARNING *** - Automatic update is activated and we are going to proceed without any notices' . "\n"); - fwrite(self::$debugHandler, '*** WARNING *** - all new settings etc. will be stored with the default value, that might not always be right for your system!' . "\n"); - fwrite(self::$debugHandler, "*** WARNING *** - If you don't want this to happen in the future consider removing the --allow-autoupdate flag from the cronjob\n"); - // including update procedures - define('_CRON_UPDATE', 1); - include_once Froxlor::getInstallDir() . '/install/updatesql.php'; - // pew - everything went better than expected - self::$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, 'Automatic update done - you should check your settings to be sure everything is fine'); - fwrite(self::$debugHandler, '*** WARNING *** - Automatic update done - you should check your settings to be sure everything is fine' . "\n"); - } - } - - fwrite(self::$debugHandler, 'Froxlor version and database version are correct' . "\n"); - } - - private static function getCronModule($cronname) - { - $upd_stmt = Database::prepare(" - SELECT `cronclass` FROM `" . TABLE_PANEL_CRONRUNS . "` WHERE `cronfile` = :cron; - "); - $cron = Database::pexecute_first($upd_stmt, [ - 'cron' => $cronname - ]); - if ($cron) { - return $cron['cronclass']; - } - self::$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Requested cronjob '" . $cronname . "' could not be found."); - return false; - } - - private static function refreshUsers($jobcount = 0) - { - if ($jobcount > 0) { - if (Settings::Get('system.nssextrausers') == 1) { - Extrausers::generateFiles(self::$cronlog); - } - - // clear NSCD cache if using fcgid or fpm, #1570 - not needed for nss-extrausers - if ((Settings::Get('system.mod_fcgid') == 1 || (int)Settings::Get('phpfpm.enabled') == 1) && Settings::Get('system.nssextrausers') == 0) { - $false_val = false; - FileDir::safe_exec('nscd -i passwd 1> /dev/null', $false_val, [ - '>' - ]); - FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, [ - '>' - ]); - } - } - } - - private static function shutdown() - { - // check for cron.d-generation task and create it if necessary - CronConfig::checkCrondConfigurationFile(); - - if (Settings::Get('logger.log_cron') == '1') { - FroxlorLogger::getInstanceOf()->setCronLog(0); - fwrite(self::$debugHandler, 'Logging for cron has been shutdown' . "\n"); - } - - fclose(self::$debugHandler); - - if (Settings::Get('system.debug_cron') != '1') { - unlink(self::getLockfile()); - } - } -} diff --git a/lib/Froxlor/FroxlorLogger.php b/lib/Froxlor/FroxlorLogger.php index 959fb7ca..dcc2eb2f 100644 --- a/lib/Froxlor/FroxlorLogger.php +++ b/lib/Froxlor/FroxlorLogger.php @@ -258,30 +258,28 @@ class FroxlorLogger /** * Set whether to log cron-runs * - * @param bool $_cronlog + * @param int $cronlog * - * @return boolean + * @return int */ - public function setCronLog($_cronlog = 0) + public function setCronLog(int $cronlog = 0) { - $_cronlog = (int)$_cronlog; - - if ($_cronlog < 0 || $_cronlog > 2) { - $_cronlog = 0; + if ($cronlog < 0 || $cronlog > 2) { + $cronlog = 0; } - Settings::Set('logger.log_cron', $_cronlog); - return $_cronlog; + Settings::Set('logger.log_cron', $cronlog); + return $cronlog; } /** * setter for crondebug-flag * - * @param bool $_flag + * @param bool $flag * * @return void */ - public function setCronDebugFlag($_flag = false) + public function setCronDebugFlag(bool $flag = false) { - self::$crondebug_flag = (bool)$_flag; + self::$crondebug_flag = $flag; } } diff --git a/lib/Froxlor/UI/Linker.php b/lib/Froxlor/UI/Linker.php index eb8e2bea..6de28b26 100644 --- a/lib/Froxlor/UI/Linker.php +++ b/lib/Froxlor/UI/Linker.php @@ -153,7 +153,7 @@ class Linker } // Encode parameters and add them to the link - $link .= urlencode($key) . (!empty($value) ? '=' . urlencode($value) : ''); + $link .= urlencode($key) . ($value !== "" ? '=' . urlencode($value) : ''); } // Reset our class for further use diff --git a/lib/configfiles/bionic.xml b/lib/configfiles/bionic.xml index 021d7423..231e85dd 100644 --- a/lib/configfiles/bionic.xml +++ b/lib/configfiles/bionic.xml @@ -4646,7 +4646,7 @@ aliases: files - + - + - scripts/froxlor_master_cronjob.php --run-task 99]]> + bin/froxlor-cli froxlor:cron --run-task 99]]> diff --git a/lib/configfiles/bullseye.xml b/lib/configfiles/bullseye.xml index 2b7e201b..18dcbe5d 100644 --- a/lib/configfiles/bullseye.xml +++ b/lib/configfiles/bullseye.xml @@ -4857,7 +4857,7 @@ aliases: files - + - + - scripts/froxlor_master_cronjob.php --run-task 99]]> + bin/froxlor-cli froxlor:cron --run-task 99]]> diff --git a/lib/configfiles/buster.xml b/lib/configfiles/buster.xml index cfb9c3e1..e28d4033 100644 --- a/lib/configfiles/buster.xml +++ b/lib/configfiles/buster.xml @@ -4848,7 +4848,7 @@ aliases: files - + - + - scripts/froxlor_master_cronjob.php --run-task 99]]> + bin/froxlor-cli froxlor:cron --run-task 99]]> diff --git a/lib/configfiles/focal.xml b/lib/configfiles/focal.xml index 8adca449..ccdfb0af 100644 --- a/lib/configfiles/focal.xml +++ b/lib/configfiles/focal.xml @@ -4071,7 +4071,7 @@ aliases: files - + - + - scripts/froxlor_master_cronjob.php --run-task 99]]> + bin/froxlor-cli froxlor:cron --run-task 99]]> diff --git a/lib/configfiles/gentoo.xml b/lib/configfiles/gentoo.xml index 2f63c357..9f25e4ab 100644 --- a/lib/configfiles/gentoo.xml +++ b/lib/configfiles/gentoo.xml @@ -3859,7 +3859,7 @@ aliases: files - + - + - scripts/froxlor_master_cronjob.php --run-task 99]]> + bin/froxlor-cli froxlor:cron --run-task 99]]> diff --git a/lib/init.php b/lib/init.php index b4fe63b5..6e90ff2d 100644 --- a/lib/init.php +++ b/lib/init.php @@ -62,6 +62,7 @@ use Froxlor\UI\Linker; use Froxlor\UI\Panel\UI; use Froxlor\UI\Request; use Froxlor\UI\Response; +use Froxlor\Install\Update; // include MySQL-tabledefinitions require Froxlor::getInstallDir() . '/lib/tables.inc.php'; @@ -153,13 +154,14 @@ UI::setLinker($linker); /** * Global Theme-variable */ -$theme = (Settings::Get('panel.default_theme') !== null) ? Settings::Get('panel.default_theme') : $_deftheme; - -/** - * Overwrite with customer/admin theme if defined - */ -if (CurrentUser::hasSession() && CurrentUser::getField('theme') != $theme) { - $theme = CurrentUser::getField('theme'); +if (Update::versionInUpdate(Settings::Get('panel.version'), '0.11.0-dev1')) { + $theme = $_deftheme; +} else { + $theme = (Settings::Get('panel.default_theme') !== null) ? Settings::Get('panel.default_theme') : $_deftheme; + // Overwrite with customer/admin theme if defined + if (CurrentUser::hasSession() && CurrentUser::getField('theme') != $theme) { + $theme = CurrentUser::getField('theme'); + } } // Check if a different variant of the theme is used diff --git a/lng/de.lng.php b/lng/de.lng.php index bab12045..71c244a0 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -1559,12 +1559,6 @@ Vielen Dank, Ihr Administrator', 'title' => 'Erlaube Verschieben von Domains unter Kunden', 'description' => 'Wenn diese Option aktiviert ist, kann unter Domaineinstellungen die Domain einem anderen Kunden zugewiesen werden.
Achtung: Der Dokumenten-Pfad der Domain wird auf den Heimatpfad (+ Domain-Ordner, sofern aktiviert) des neuen Kunden gesetzt.', ], - 'cron' => [ - 'debug' => [ - 'title' => 'Debuggen des Cronscripts', - 'description' => 'Wenn aktiviert, wird die Lockdatei nach dem Cronlauf zum Debuggen nicht gelöscht
Achtung: Eine alte Lockdatei kann weitere Cronjobs behindern und dafür sorgen, dass diese nicht vollständig ausgeführt werden.', - ], - ], 'specialsettingsforsubdomains' => [ 'description' => 'Wenn ja, werden die individuellen Einstellungen für alle Subdomains übernommen.
Wenn nein, werden Subdomain-Specialsettings entfernt.', ], diff --git a/lng/en.lng.php b/lng/en.lng.php index d5a5632f..ac6fcc82 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -1935,12 +1935,6 @@ Yours sincerely, your administrator', 'title' => 'Allow moving domains between customers', 'description' => 'If activated you can change the customer of a domain at domainsettings.
Attention: Froxlor changes the documentroot to the new customer\'s default homedir (+ domain-folder if activated)', ], - 'cron' => [ - 'debug' => [ - 'title' => 'Cronscript debugging', - 'description' => 'Activate to keep the lockfile after a cron-run for debugging.
Attention:Keeping the lockfile can cause the next scheduled cron not to run properly.', - ], - ], 'specialsettingsforsubdomains' => [ 'description' => 'If yes these custom vHost-settings will be added to all subdomains; if no subdomain-specialsettings are being removed.', ], diff --git a/scripts/froxlor_master_cronjob.php b/scripts/froxlor_master_cronjob.php deleted file mode 100644 index 99a091ae..00000000 --- a/scripts/froxlor_master_cronjob.php +++ /dev/null @@ -1,34 +0,0 @@ - - * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 - */ - -// validate correct php version -if (version_compare("7.4.0", PHP_VERSION, ">=")) { - die('Froxlor requires at least php-7.4. Please validate that your php-cli version and the cron execution command are correct.'); -} - -require dirname(__DIR__) . '/vendor/autoload.php'; - -\Froxlor\Cron\MasterCron::setArguments($argv); -\Froxlor\Cron\MasterCron::run(); diff --git a/scripts/index.html b/scripts/index.html deleted file mode 100644 index e69de29b..00000000 From 50e35e149c9d41b054fa157f2769286dcacb0a4f Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 10 Aug 2022 00:17:11 +0200 Subject: [PATCH 02/11] various minor bugfixes; composer requirements update Signed-off-by: Michael Kaufmann --- 2fa.php | 1 + admin_templates.php | 1 + admin_updates.php | 31 +- composer.json | 4 +- composer.lock | 359 +++++++++++-------- install/updatesql.php | 5 - lib/Froxlor/Api/ApiCommand.php | 2 +- lib/Froxlor/Api/Commands/Admins.php | 3 +- lib/Froxlor/Api/Commands/Certificates.php | 3 +- lib/Froxlor/Api/Commands/Cronjobs.php | 3 +- lib/Froxlor/Api/Commands/CustomerBackups.php | 2 +- lib/Froxlor/Api/Commands/Customers.php | 3 +- lib/Froxlor/Api/Commands/DirOptions.php | 3 +- lib/Froxlor/Api/Commands/DirProtections.php | 3 +- lib/Froxlor/Api/Commands/DomainZones.php | 3 +- lib/Froxlor/Api/Commands/Domains.php | 3 - lib/Froxlor/Api/Commands/EmailAccounts.php | 1 - lib/Froxlor/Api/Commands/EmailForwarders.php | 2 +- lib/Froxlor/Api/Commands/Emails.php | 3 +- lib/Froxlor/Api/Commands/FpmDaemons.php | 3 +- lib/Froxlor/Api/Commands/Ftps.php | 3 +- lib/Froxlor/Api/Commands/HostingPlans.php | 3 +- lib/Froxlor/Api/Commands/IpsAndPorts.php | 3 +- lib/Froxlor/Api/Commands/MysqlServer.php | 19 +- lib/Froxlor/Api/Commands/Mysqls.php | 3 +- lib/Froxlor/Api/Commands/PhpSettings.php | 3 +- lib/Froxlor/Api/Commands/SubDomains.php | 3 +- lib/Froxlor/Api/Commands/SysLog.php | 3 +- lib/Froxlor/Bulk/BulkAction.php | 4 +- lib/Froxlor/Bulk/DomainBulkAction.php | 8 +- lib/Froxlor/Cli/CliCommand.php | 3 +- lib/Froxlor/Cli/MasterCron.php | 6 +- lib/Froxlor/Cli/UpdateCommand.php | 4 +- lib/Froxlor/Config/ConfigDaemon.php | 2 + lib/Froxlor/Cron/Http/Apache.php | 8 - lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php | 5 +- lib/Froxlor/Cron/Http/Lighttpd.php | 58 ++- lib/Froxlor/Cron/Http/Nginx.php | 23 +- lib/Froxlor/Cron/Http/Php/PhpInterface.php | 28 +- lib/Froxlor/Database/Database.php | 3 + lib/Froxlor/FileDir.php | 36 +- lib/Froxlor/Install/AutoUpdate.php | 1 + lib/Froxlor/Install/Update.php | 43 ++- lib/Froxlor/UI/Listing.php | 1 - lib/Froxlor/Validate/Validate.php | 40 +-- 45 files changed, 397 insertions(+), 354 deletions(-) diff --git a/2fa.php b/2fa.php index 9c7cfb9a..3155db27 100644 --- a/2fa.php +++ b/2fa.php @@ -35,6 +35,7 @@ use Froxlor\Settings; use Froxlor\UI\Panel\UI; use Froxlor\UI\Response; use Froxlor\PhpHelper; +use Froxlor\User; if (Settings::Get('2fa.enabled') != '1') { Response::dynamicError('2fa.2fa_not_activated'); diff --git a/admin_templates.php b/admin_templates.php index 5d82ee96..db77e612 100644 --- a/admin_templates.php +++ b/admin_templates.php @@ -37,6 +37,7 @@ use Froxlor\UI\Panel\UI; use Froxlor\UI\Request; use Froxlor\UI\Response; use Froxlor\Validate\Validate; +use Froxlor\CurrentUser; $id = (int)Request::get('id'); $subjectid = intval(Request::get('subjectid')); diff --git a/admin_updates.php b/admin_updates.php index e99d3e3e..acdf1ebb 100644 --- a/admin_updates.php +++ b/admin_updates.php @@ -26,11 +26,12 @@ const AREA = 'admin'; require __DIR__ . '/lib/init.php'; +use Exception; use Froxlor\Cron\TaskId; -use Froxlor\Database\Database; use Froxlor\Froxlor; use Froxlor\FroxlorLogger; use Froxlor\Install\Preconfig; +use Froxlor\Install\Update; use Froxlor\Settings; use Froxlor\System\Cronjob; use Froxlor\UI\Panel\UI; @@ -40,32 +41,8 @@ use Froxlor\User; if ($page == 'overview') { $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_updates"); - /** - * this is a dirty hack but syscp 1.4.2.1 does not - * have any version/dbversion in the database (don't know why) - * so we have to set them both to run a correct upgrade - */ if (!Froxlor::isFroxlor()) { - if (Settings::Get('panel.version') == null || Settings::Get('panel.version') == '') { - Settings::Set('panel.version', '1.4.2.1'); - } - if (Settings::Get('system.dbversion') == null || Settings::Get('system.dbversion') == '') { - /** - * for syscp-stable (1.4.2.1) this value has to be 0 - * so the required table-fields are added correctly - * and the svn-version has its value in the database - * -> bug #54 - */ - $result_stmt = Database::query(" - SELECT `value` FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `varname` = 'dbversion'"); - $result = $result_stmt->fetch(PDO::FETCH_ASSOC); - - if (isset($result['value'])) { - Settings::Set('system.dbversion', (int)$result['value'], false); - } else { - Settings::Set('system.dbversion', 0, false); - } - } + throw new Exception('SysCP/customized upgrades are not supported'); } if (Froxlor::hasDbUpdates() || Froxlor::hasUpdates()) { @@ -81,7 +58,7 @@ if ($page == 'overview') { @chmod(Froxlor::getInstallDir() . '/lib/userdata.inc.php', 0400); UI::view('install/update.html.twig', [ - 'checks' => $update_tasks + 'checks' => Update::getUpdateTasks() ]); exit; } else { diff --git a/composer.json b/composer.json index 1e960edf..cf2e1942 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,6 @@ "email": "team@froxlor.org", "issues": "https://github.com/Froxlor/Froxlor/issues", "forum": "https://forum.froxlor.org/", - "irc": "irc://irc.libera.chat/froxlor", "source": "https://github.com/Froxlor/Froxlor", "docs": "https://docs.froxlor.org/", "chat": "https://discord.froxlor.org/" @@ -64,7 +63,8 @@ "sebastian/phpcpd": "^6.0", "phploc/phploc": "^7.0", "phpmd/phpmd": "^2.10", - "phpunit/php-timer" : "^5" + "phpunit/php-timer" : "^5", + "phpstan/phpstan": "^1.8" }, "suggest": { "ext-bcmath": "*", diff --git a/composer.lock b/composer.lock index cab706ae..66490695 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "050664b27120307bec7721bac4ecb395", + "content-hash": "f8370edea3c85bcb7b681926a1fff04e", "packages": [ { "name": "erusev/parsedown", @@ -114,16 +114,16 @@ }, { "name": "monolog/monolog", - "version": "1.27.0", + "version": "1.27.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "52ebd235c1f7e0d5e1b16464b695a28335f8e44a" + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/52ebd235c1f7e0d5e1b16464b695a28335f8e44a", - "reference": "52ebd235c1f7e0d5e1b16464b695a28335f8e44a", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", "shasum": "" }, "require": { @@ -184,7 +184,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.27.0" + "source": "https://github.com/Seldaek/monolog/tree/1.27.1" }, "funding": [ { @@ -196,20 +196,20 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:29:46+00:00" + "time": "2022-06-09T08:53:42+00:00" }, { "name": "phpmailer/phpmailer", - "version": "v6.6.0", + "version": "v6.6.3", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "e43bac82edc26ca04b36143a48bde1c051cfd5b1" + "reference": "9400f305a898f194caff5521f64e5dfa926626f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/e43bac82edc26ca04b36143a48bde1c051cfd5b1", - "reference": "e43bac82edc26ca04b36143a48bde1c051cfd5b1", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/9400f305a898f194caff5521f64e5dfa926626f3", + "reference": "9400f305a898f194caff5521f64e5dfa926626f3", "shasum": "" }, "require": { @@ -221,8 +221,8 @@ "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "doctrine/annotations": "^1.2", - "php-parallel-lint/php-console-highlighter": "^0.5.0", - "php-parallel-lint/php-parallel-lint": "^1.3.1", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", "phpcompatibility/php-compatibility": "^9.3.5", "roave/security-advisories": "dev-latest", "squizlabs/php_codesniffer": "^3.6.2", @@ -266,7 +266,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.0" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.3" }, "funding": [ { @@ -274,7 +274,7 @@ "type": "github" } ], - "time": "2022-02-28T15:31:21+00:00" + "time": "2022-06-20T09:21:02+00:00" }, { "name": "psr/container", @@ -446,16 +446,16 @@ }, { "name": "symfony/console", - "version": "v5.4.7", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6" + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/900275254f0a1a2afff1ab0e11abd5587a10e1d6", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6", + "url": "https://api.github.com/repos/symfony/console/zipball/535846c7ee6bc4dd027ca0d93220601456734b10", + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10", "shasum": "" }, "require": { @@ -525,7 +525,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.7" + "source": "https://github.com/symfony/console/tree/v5.4.11" }, "funding": [ { @@ -541,11 +541,11 @@ "type": "tidelift" } ], - "time": "2022-03-31T17:09:19+00:00" + "time": "2022-07-22T10:42:43+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -592,7 +592,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -612,16 +612,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", "shasum": "" }, "require": { @@ -636,7 +636,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -674,7 +674,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" }, "funding": [ { @@ -690,20 +690,20 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40" + "reference": "143f1881e655bebca1312722af8068de235ae5dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f1aed619e28cb077fc83fac8c4c0383578356e40", - "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/143f1881e655bebca1312722af8068de235ae5dc", + "reference": "143f1881e655bebca1312722af8068de235ae5dc", "shasum": "" }, "require": { @@ -718,7 +718,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -757,7 +757,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.26.0" }, "funding": [ { @@ -773,20 +773,20 @@ "type": "tidelift" } ], - "time": "2022-01-04T09:04:05+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "433d05519ce6990bf3530fba6957499d327395c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", "shasum": "" }, "require": { @@ -798,7 +798,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -838,7 +838,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" }, "funding": [ { @@ -854,20 +854,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -879,7 +879,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -922,7 +922,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -938,20 +938,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", "shasum": "" }, "require": { @@ -966,7 +966,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1005,7 +1005,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" }, "funding": [ { @@ -1021,20 +1021,20 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2", + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2", "shasum": "" }, "require": { @@ -1043,7 +1043,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1081,7 +1081,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0" }, "funding": [ { @@ -1097,20 +1097,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", "shasum": "" }, "require": { @@ -1119,7 +1119,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1160,7 +1160,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" }, "funding": [ { @@ -1176,20 +1176,20 @@ "type": "tidelift" } ], - "time": "2021-06-05T21:20:04+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", "shasum": "" }, "require": { @@ -1198,7 +1198,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1243,7 +1243,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" }, "funding": [ { @@ -1259,20 +1259,20 @@ "type": "tidelift" } ], - "time": "2022-03-04T08:16:47+00:00" + "time": "2022-05-10T07:21:04+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", "shasum": "" }, "require": { @@ -1326,7 +1326,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" }, "funding": [ { @@ -1342,20 +1342,20 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:07:29+00:00" + "time": "2022-05-30T19:17:29+00:00" }, { "name": "symfony/string", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10" + "reference": "5eb661e49ad389e4ae2b6e4df8d783a8a6548322" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10", + "url": "https://api.github.com/repos/symfony/string/zipball/5eb661e49ad389e4ae2b6e4df8d783a8a6548322", + "reference": "5eb661e49ad389e4ae2b6e4df8d783a8a6548322", "shasum": "" }, "require": { @@ -1412,7 +1412,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.3" + "source": "https://github.com/symfony/string/tree/v5.4.11" }, "funding": [ { @@ -1428,20 +1428,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-07-24T16:15:25+00:00" }, { "name": "twig/twig", - "version": "v3.3.10", + "version": "v3.4.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "8442df056c51b706793adf80a9fd363406dd3674" + "reference": "e939eae92386b69b49cfa4599dd9bead6bf4a342" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/8442df056c51b706793adf80a9fd363406dd3674", - "reference": "8442df056c51b706793adf80a9fd363406dd3674", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/e939eae92386b69b49cfa4599dd9bead6bf4a342", + "reference": "e939eae92386b69b49cfa4599dd9bead6bf4a342", "shasum": "" }, "require": { @@ -1456,7 +1456,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -1492,7 +1492,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.3.10" + "source": "https://github.com/twigphp/Twig/tree/v3.4.1" }, "funding": [ { @@ -1504,7 +1504,7 @@ "type": "tidelift" } ], - "time": "2022-04-06T06:47:41+00:00" + "time": "2022-05-17T05:48:52+00:00" }, { "name": "voku/anti-xss", @@ -2032,16 +2032,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.2", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/34bea19b6e03d8153165d8f30bba4c3be86184c1", + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1", "shasum": "" }, "require": { @@ -2082,9 +2082,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.14.0" }, - "time": "2021-11-30T19:35:32+00:00" + "time": "2022-05-31T20:59:12+00:00" }, { "name": "pdepend/pdepend", @@ -2687,6 +2687,65 @@ }, "time": "2021-12-08T12:19:24+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "c53312ecc575caf07b0e90dee43883fdf90ca67c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c53312ecc575caf07b0e90dee43883fdf90ca67c", + "reference": "c53312ecc575caf07b0e90dee43883fdf90ca67c", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.8.2" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpstan", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:57:31+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.15", @@ -3007,16 +3066,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.20", + "version": "9.5.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba" + "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba", - "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0e32b76be457de00e83213528f6bb37e2a38fcb1", + "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1", "shasum": "" }, "require": { @@ -3050,7 +3109,6 @@ "sebastian/version": "^3.0.2" }, "require-dev": { - "ext-pdo": "*", "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { @@ -3094,7 +3152,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.21" }, "funding": [ { @@ -3106,7 +3164,7 @@ "type": "github" } ], - "time": "2022-04-01T12:37:26+00:00" + "time": "2022-06-19T12:14:25+00:00" }, { "name": "sebastian/cli-parser", @@ -4135,16 +4193,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.6.2", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", "shasum": "" }, "require": { @@ -4187,20 +4245,20 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2021-12-12T21:44:58+00:00" + "time": "2022-06-18T07:21:10+00:00" }, { "name": "symfony/config", - "version": "v5.4.7", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "05624c386afa1b4ccc1357463d830fade8d9d404" + "reference": "ec79e03125c1d2477e43dde8528535d90cc78379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/05624c386afa1b4ccc1357463d830fade8d9d404", - "reference": "05624c386afa1b4ccc1357463d830fade8d9d404", + "url": "https://api.github.com/repos/symfony/config/zipball/ec79e03125c1d2477e43dde8528535d90cc78379", + "reference": "ec79e03125c1d2477e43dde8528535d90cc78379", "shasum": "" }, "require": { @@ -4250,7 +4308,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.7" + "source": "https://github.com/symfony/config/tree/v5.4.11" }, "funding": [ { @@ -4266,20 +4324,20 @@ "type": "tidelift" } ], - "time": "2022-03-21T13:42:03+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.4.7", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "35588b2afb08ea3a142d62fefdcad4cb09be06ed" + "reference": "a8b9251016e9476db73e25fa836904bc0bf74c62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/35588b2afb08ea3a142d62fefdcad4cb09be06ed", - "reference": "35588b2afb08ea3a142d62fefdcad4cb09be06ed", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a8b9251016e9476db73e25fa836904bc0bf74c62", + "reference": "a8b9251016e9476db73e25fa836904bc0bf74c62", "shasum": "" }, "require": { @@ -4339,7 +4397,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.7" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.11" }, "funding": [ { @@ -4355,20 +4413,20 @@ "type": "tidelift" } ], - "time": "2022-03-08T15:43:06+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.7", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f" + "reference": "6699fb0228d1bc35b12aed6dd5e7455457609ddd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3a4442138d80c9f7b600fb297534ac718b61d37f", - "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/6699fb0228d1bc35b12aed6dd5e7455457609ddd", + "reference": "6699fb0228d1bc35b12aed6dd5e7455457609ddd", "shasum": "" }, "require": { @@ -4403,7 +4461,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.7" + "source": "https://github.com/symfony/filesystem/tree/v5.4.11" }, "funding": [ { @@ -4419,20 +4477,20 @@ "type": "tidelift" } ], - "time": "2022-04-01T12:33:59+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.25.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1", "shasum": "" }, "require": { @@ -4441,7 +4499,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4482,7 +4540,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0" }, "funding": [ { @@ -4498,7 +4556,7 @@ "type": "tidelift" } ], - "time": "2021-09-13T13:58:11+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "theseer/tokenizer", @@ -4552,21 +4610,21 @@ }, { "name": "webmozart/assert", - "version": "1.10.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" + "ext-ctype": "*", + "php": "^7.2 || ^8.0" }, "conflict": { "phpstan/phpstan": "<0.12.20", @@ -4604,9 +4662,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" + "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, - "time": "2021-03-09T10:59:23+00:00" + "time": "2022-06-03T18:03:27+00:00" } ], "aliases": [], @@ -4628,7 +4686,8 @@ "ext-curl": "*", "ext-json": "*", "ext-openssl": "*", - "ext-fileinfo": "*" + "ext-fileinfo": "*", + "ext-gmp": "*" }, "platform-dev": { "ext-pcntl": "*" diff --git a/install/updatesql.php b/install/updatesql.php index d7e5ae56..52913846 100644 --- a/install/updatesql.php +++ b/install/updatesql.php @@ -51,12 +51,7 @@ try { if (Froxlor::isFroxlor()) { - // will be filled and increased by the update include-files below - $update_tasks = []; - $task_counter = 0; - include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_0.10.inc.php')); - include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_0.11.inc.php')); // Check Froxlor - database integrity (only happens after all updates are done, so we know the db-layout is okay) diff --git a/lib/Froxlor/Api/ApiCommand.php b/lib/Froxlor/Api/ApiCommand.php index 680ce36f..ca530273 100644 --- a/lib/Froxlor/Api/ApiCommand.php +++ b/lib/Froxlor/Api/ApiCommand.php @@ -105,7 +105,7 @@ abstract class ApiCommand extends ApiParameter * * @throws Exception */ - public function __construct($header = null, $params = null, $userinfo = null, $internal = false) + final public function __construct($header = null, $params = null, $userinfo = null, $internal = false) { parent::__construct($params); diff --git a/lib/Froxlor/Api/Commands/Admins.php b/lib/Froxlor/Api/Commands/Admins.php index 5f9ba445..8c2b516e 100644 --- a/lib/Froxlor/Api/Commands/Admins.php +++ b/lib/Froxlor/Api/Commands/Admins.php @@ -117,7 +117,7 @@ class Admins extends ApiCommand implements ResourceEntity * returns the total number of admins for the given admin * * @access admin - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -131,6 +131,7 @@ class Admins extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_admins']); } + $this->response(0); } throw new Exception("Not allowed to execute given command.", 403); } diff --git a/lib/Froxlor/Api/Commands/Certificates.php b/lib/Froxlor/Api/Commands/Certificates.php index a4c600da..7784b0c3 100644 --- a/lib/Froxlor/Api/Commands/Certificates.php +++ b/lib/Froxlor/Api/Commands/Certificates.php @@ -371,7 +371,7 @@ class Certificates extends ApiCommand implements ResourceEntity * returns the total number of certificates for the given user * * @access admin, customer - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -399,6 +399,7 @@ class Certificates extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_certs']); } + return $this->response(0); } /** diff --git a/lib/Froxlor/Api/Commands/Cronjobs.php b/lib/Froxlor/Api/Commands/Cronjobs.php index 6fd3bed5..2584aef5 100644 --- a/lib/Froxlor/Api/Commands/Cronjobs.php +++ b/lib/Froxlor/Api/Commands/Cronjobs.php @@ -185,7 +185,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity * returns the total number of cronjobs * * @access admin - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -198,6 +198,7 @@ class Cronjobs extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_crons']); } + return $this->response(0); } throw new Exception("Not allowed to execute given command.", 403); } diff --git a/lib/Froxlor/Api/Commands/CustomerBackups.php b/lib/Froxlor/Api/Commands/CustomerBackups.php index 124532b0..efbbaa66 100644 --- a/lib/Froxlor/Api/Commands/CustomerBackups.php +++ b/lib/Froxlor/Api/Commands/CustomerBackups.php @@ -210,7 +210,7 @@ class CustomerBackups extends ApiCommand implements ResourceEntity * optional, admin-only, select backup-jobs of a specific customer by loginname * * @access admin, customer - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index 0eeb8ffd..82789b24 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -143,7 +143,7 @@ class Customers extends ApiCommand implements ResourceEntity * returns the total number of customers for the given admin * * @access admin - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -163,6 +163,7 @@ class Customers extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_customers']); } + return $this->response(0); } throw new Exception("Not allowed to execute given command.", 403); } diff --git a/lib/Froxlor/Api/Commands/DirOptions.php b/lib/Froxlor/Api/Commands/DirOptions.php index c0a700ea..c39507ec 100644 --- a/lib/Froxlor/Api/Commands/DirOptions.php +++ b/lib/Froxlor/Api/Commands/DirOptions.php @@ -396,7 +396,7 @@ class DirOptions extends ApiCommand implements ResourceEntity * optional, admin-only, select directory-protections of a specific customer by loginname * * @access admin, customer - * @return string json-encoded array count|list + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -415,6 +415,7 @@ class DirOptions extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_htaccess']); } + return $this->response(0); } /** diff --git a/lib/Froxlor/Api/Commands/DirProtections.php b/lib/Froxlor/Api/Commands/DirProtections.php index f4964993..8b478103 100644 --- a/lib/Froxlor/Api/Commands/DirProtections.php +++ b/lib/Froxlor/Api/Commands/DirProtections.php @@ -339,7 +339,7 @@ class DirProtections extends ApiCommand implements ResourceEntity * optional, admin-only, select directory-protections of a specific customer by loginname * * @access admin, customer - * @return string json-encoded array count|list + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -358,6 +358,7 @@ class DirProtections extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_htpasswd']); } + return $this->response(0); } /** diff --git a/lib/Froxlor/Api/Commands/DomainZones.php b/lib/Froxlor/Api/Commands/DomainZones.php index eafdd0d4..e8e2163e 100644 --- a/lib/Froxlor/Api/Commands/DomainZones.php +++ b/lib/Froxlor/Api/Commands/DomainZones.php @@ -491,7 +491,7 @@ class DomainZones extends ApiCommand implements ResourceEntity * optional, the domain name * * @access admin, customer - * @return bool + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -522,6 +522,7 @@ class DomainZones extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_dns']); } + return $this->response(0); } /** diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index 44cc6b4b..00ee01c2 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -1743,9 +1743,6 @@ class Domains extends ApiCommand implements ResourceEntity $upd_specialsettings = ", `specialsettings` = :specialsettings, `ssl_specialsettings` = :ssl_specialsettings, `include_specialsettings` = :include_specialsettings "; } else { $upd_specialsettings = ''; - unset($_update_data['specialsettings']); - unset($_update_data['ssl_specialsettings']); - unset($_update_data['include_specialsettings']); $upd_stmt = Database::prepare(" UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `specialsettings`='', `ssl_specialsettings`='', `include_specialsettings`='0' WHERE `parentdomainid` = :id "); diff --git a/lib/Froxlor/Api/Commands/EmailAccounts.php b/lib/Froxlor/Api/Commands/EmailAccounts.php index 74e11177..079e4eea 100644 --- a/lib/Froxlor/Api/Commands/EmailAccounts.php +++ b/lib/Froxlor/Api/Commands/EmailAccounts.php @@ -216,7 +216,6 @@ class EmailAccounts extends ApiCommand implements ResourceEntity // replacer array for mail to create account on server $replace_arr = [ 'EMAIL' => $email_full, - 'USERNAME' => $username, 'PASSWORD' => htmlentities(htmlentities($password)), 'SALUTATION' => User::getCorrectUserSalutation($customer), 'NAME' => $customer['name'], diff --git a/lib/Froxlor/Api/Commands/EmailForwarders.php b/lib/Froxlor/Api/Commands/EmailForwarders.php index a190ee1d..520fd05c 100644 --- a/lib/Froxlor/Api/Commands/EmailForwarders.php +++ b/lib/Froxlor/Api/Commands/EmailForwarders.php @@ -206,7 +206,7 @@ class EmailForwarders extends ApiCommand implements ResourceEntity * optional, admin-only, the loginname * * @access admin,customer - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php index 5b083b16..f4b1a524 100644 --- a/lib/Froxlor/Api/Commands/Emails.php +++ b/lib/Froxlor/Api/Commands/Emails.php @@ -356,7 +356,7 @@ class Emails extends ApiCommand implements ResourceEntity * optional, admin-only, select email addresses of a specific customer by loginname * * @access admin, customer - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -373,6 +373,7 @@ class Emails extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_emails']); } + return $this->response(0); } /** diff --git a/lib/Froxlor/Api/Commands/FpmDaemons.php b/lib/Froxlor/Api/Commands/FpmDaemons.php index 85cd3145..c5aec829 100644 --- a/lib/Froxlor/Api/Commands/FpmDaemons.php +++ b/lib/Froxlor/Api/Commands/FpmDaemons.php @@ -105,7 +105,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity * returns the total number of accessible fpm daemons * * @access admin - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -118,6 +118,7 @@ class FpmDaemons extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_fpms']); } + return $this->response(0); } throw new Exception("Not allowed to execute given command.", 403); } diff --git a/lib/Froxlor/Api/Commands/Ftps.php b/lib/Froxlor/Api/Commands/Ftps.php index 15020139..5a709756 100644 --- a/lib/Froxlor/Api/Commands/Ftps.php +++ b/lib/Froxlor/Api/Commands/Ftps.php @@ -549,7 +549,7 @@ class Ftps extends ApiCommand implements ResourceEntity * optional, admin-only, select ftp-users of a specific customer by loginname * * @access admin, customer - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -564,6 +564,7 @@ class Ftps extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_ftps']); } + return $this->response(0); } /** diff --git a/lib/Froxlor/Api/Commands/HostingPlans.php b/lib/Froxlor/Api/Commands/HostingPlans.php index 0cd0c560..7fde4652 100644 --- a/lib/Froxlor/Api/Commands/HostingPlans.php +++ b/lib/Froxlor/Api/Commands/HostingPlans.php @@ -89,7 +89,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity * returns the total number of accessible hosting plans * * @access admin - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -107,6 +107,7 @@ class HostingPlans extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_plans']); } + return $this->response(0); } throw new Exception("Not allowed to execute given command.", 403); } diff --git a/lib/Froxlor/Api/Commands/IpsAndPorts.php b/lib/Froxlor/Api/Commands/IpsAndPorts.php index 5c2a25f6..579614cb 100644 --- a/lib/Froxlor/Api/Commands/IpsAndPorts.php +++ b/lib/Froxlor/Api/Commands/IpsAndPorts.php @@ -92,7 +92,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity * returns the total number of accessible ip/port entries * * @access admin - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -108,6 +108,7 @@ class IpsAndPorts extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_ips']); } + return $this->response(0); } throw new Exception("Not allowed to execute given command.", 403); } diff --git a/lib/Froxlor/Api/Commands/MysqlServer.php b/lib/Froxlor/Api/Commands/MysqlServer.php index cd2289f8..89f15c50 100644 --- a/lib/Froxlor/Api/Commands/MysqlServer.php +++ b/lib/Froxlor/Api/Commands/MysqlServer.php @@ -124,6 +124,9 @@ class MysqlServer extends ApiCommand implements ResourceEntity } } + $sql = []; + $sql_root = []; + // get all data from lib/userdata require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; @@ -222,6 +225,8 @@ class MysqlServer extends ApiCommand implements ResourceEntity */ public function listing() { + $sql = []; + $sql_root = []; // get all data from lib/userdata require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; @@ -255,7 +260,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity * returns the total number of mysql servers * * @access admin, customer - * @return string json-encoded array + * @return string json-encoded response message */ public function listingCount() { @@ -266,6 +271,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity } return $this->response(0); } + $sql_root = []; // get all data from lib/userdata require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; return $this->response(count($sql_root)); @@ -290,9 +296,14 @@ class MysqlServer extends ApiCommand implements ResourceEntity $dbserver = (int) $this->getParam('dbserver', $dn_optional, -1); $dbserver = $id >= 0 ? $id : $dbserver; + $sql_root = []; // get all data from lib/userdata require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; + if (!isset($sql_root[$dbserver])) { + throw new Exception('Mysql server not found', 404); + } + // limit customer to its allowed servers if ($this->isAdmin() == false) { $allowed_mysqls = json_decode($this->getUserDetail('allowed_mysqlserver'), true); @@ -300,11 +311,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity throw new Exception("You cannot access this resource", 405); } // no usernames required for non-admins - unset($sqlrootdata['user']); - } - - if (!isset($sql_root[$dbserver])) { - throw new Exception('Mysql server not found', 404); + unset($sql_root[$dbserver]['user']); } unset($sql_root[$dbserver]['password']); diff --git a/lib/Froxlor/Api/Commands/Mysqls.php b/lib/Froxlor/Api/Commands/Mysqls.php index 89907da9..0708077f 100644 --- a/lib/Froxlor/Api/Commands/Mysqls.php +++ b/lib/Froxlor/Api/Commands/Mysqls.php @@ -481,7 +481,7 @@ class Mysqls extends ApiCommand implements ResourceEntity * optional, admin-only, select dbs of a specific customer by loginname * * @access admin, customer - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -495,6 +495,7 @@ class Mysqls extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_dbs']); } + return $this->response(0); } /** diff --git a/lib/Froxlor/Api/Commands/PhpSettings.php b/lib/Froxlor/Api/Commands/PhpSettings.php index 6d244daf..86d9b562 100644 --- a/lib/Froxlor/Api/Commands/PhpSettings.php +++ b/lib/Froxlor/Api/Commands/PhpSettings.php @@ -178,7 +178,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity * returns the total number of accessible php-setting entries * * @access admin - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -192,6 +192,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_phps']); } + return $this->response(0); } throw new Exception("Not allowed to execute given command.", 403); } diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php index fd58b6f3..8f42b4c1 100644 --- a/lib/Froxlor/Api/Commands/SubDomains.php +++ b/lib/Froxlor/Api/Commands/SubDomains.php @@ -1017,7 +1017,7 @@ class SubDomains extends ApiCommand implements ResourceEntity * optional, admin-only, select (sub)domains of a specific customer by loginname * * @access admin, customer - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -1069,6 +1069,7 @@ class SubDomains extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_subdom']); } + return $this->response(0); } /** diff --git a/lib/Froxlor/Api/Commands/SysLog.php b/lib/Froxlor/Api/Commands/SysLog.php index 1428793c..c3686a54 100644 --- a/lib/Froxlor/Api/Commands/SysLog.php +++ b/lib/Froxlor/Api/Commands/SysLog.php @@ -103,7 +103,7 @@ class SysLog extends ApiCommand implements ResourceEntity * returns the total number of log-entries * * @access admin - * @return string json-encoded array + * @return string json-encoded response message * @throws Exception */ public function listingCount() @@ -150,6 +150,7 @@ class SysLog extends ApiCommand implements ResourceEntity if ($result) { return $this->response($result['num_logs']); } + return $this->response(0); } /** diff --git a/lib/Froxlor/Bulk/BulkAction.php b/lib/Froxlor/Bulk/BulkAction.php index ecb2d627..73cef92d 100644 --- a/lib/Froxlor/Bulk/BulkAction.php +++ b/lib/Froxlor/Bulk/BulkAction.php @@ -76,7 +76,7 @@ abstract class BulkAction * * @return object BulkAction instance */ - protected function __construct($import_file = null, $userinfo = []) + protected function __construct(string $import_file = null, array $userinfo = []) { if (!empty($import_file)) { $this->impFile = FileDir::makeCorrectFile($import_file); @@ -93,7 +93,7 @@ abstract class BulkAction * * @return array 'all' => amount of records processed, 'imported' => number of imported records */ - abstract public function doImport($separator = ";", $offset = 0); + abstract public function doImport(string $separator = ";", int $offset = 0); /** * setter for import-file diff --git a/lib/Froxlor/Bulk/DomainBulkAction.php b/lib/Froxlor/Bulk/DomainBulkAction.php index 155f3de4..f158dfff 100644 --- a/lib/Froxlor/Bulk/DomainBulkAction.php +++ b/lib/Froxlor/Bulk/DomainBulkAction.php @@ -34,10 +34,12 @@ class DomainBulkAction extends BulkAction { /** + * @param string $import_file + * @param array $userinfo * - * @return object DomainBulkAction instance + * @return DomainBulkAction */ - public function __construct($import_file = null, $userinfo) + public function __construct(string $import_file = null, array $userinfo = []) { parent::__construct($import_file, $userinfo); $this->setApiCall('Domains.add'); @@ -52,7 +54,7 @@ class DomainBulkAction extends BulkAction * * @return array 'all' => amount of records processed, 'imported' => number of imported records */ - public function doImport($separator = ";", $offset = 0) + public function doImport(string $separator = ";", int $offset = 0) { if ($this->userinfo['domains'] == "-1") { $dom_unlimited = true; diff --git a/lib/Froxlor/Cli/CliCommand.php b/lib/Froxlor/Cli/CliCommand.php index 36c29223..5c154a27 100644 --- a/lib/Froxlor/Cli/CliCommand.php +++ b/lib/Froxlor/Cli/CliCommand.php @@ -28,6 +28,7 @@ namespace Froxlor\Cli; use Exception; use Froxlor\Froxlor; use Froxlor\Settings; +use Froxlor\Database\Database; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -72,7 +73,7 @@ class CliCommand extends Command include_once Froxlor::getInstallDir() . '/install/updatesql.php'; ob_end_flush(); $output->writeln('Automatic update done - you should check your settings to be sure everything is fine'); - return self::SUCCCESS; + return self::SUCCESS; } private function cleanUpdateOutput($buffer) diff --git a/lib/Froxlor/Cli/MasterCron.php b/lib/Froxlor/Cli/MasterCron.php index c2c8a0ff..a3b1f384 100644 --- a/lib/Froxlor/Cli/MasterCron.php +++ b/lib/Froxlor/Cli/MasterCron.php @@ -25,6 +25,7 @@ namespace Froxlor\Cli; +use PDO; use Froxlor\Froxlor; use Froxlor\FileDir; use Froxlor\Settings; @@ -32,6 +33,7 @@ use Froxlor\FroxlorLogger; use Froxlor\Database\Database; use Froxlor\System\Cronjob; use Froxlor\Cron\TaskId; +use Froxlor\Cron\CronConfig; use Froxlor\Cron\System\Extrausers; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -142,7 +144,7 @@ final class MasterCron extends CliCommand // we have to check the system's last guid with every cron run // in case the admin installed new software which added a new user //so users in the database don't conflict with system users - $this->cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Checking system\'s last guid'); + $this->cronLog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Checking system\'s last guid'); Cronjob::checkLastGuid(); // check for cron.d-generation task and create it if necessary @@ -160,7 +162,7 @@ final class MasterCron extends CliCommand { if ($jobcount > 0) { if (Settings::Get('system.nssextrausers') == 1) { - Extrausers::generateFiles(self::$cronlog); + Extrausers::generateFiles($this->cronLog); return; } diff --git a/lib/Froxlor/Cli/UpdateCommand.php b/lib/Froxlor/Cli/UpdateCommand.php index 15d3947c..23a50905 100644 --- a/lib/Froxlor/Cli/UpdateCommand.php +++ b/lib/Froxlor/Cli/UpdateCommand.php @@ -143,7 +143,7 @@ final class UpdateCommand extends CliCommand $auex = AutoUpdate::extractZip($audl); if ($auex == 0) { $output->writeln("Froxlor files updated successfully."); - $result = self::SUCCCESS; + $result = self::SUCCESS; $question = new ConfirmationQuestion('Update database? [no] ', false, '/^(y|j)/i'); if ($yestoall || $helper->ask($input, $output, $question)) { $result = $this->updateDatabase(); @@ -193,7 +193,7 @@ final class UpdateCommand extends CliCommand ]); include_once Froxlor::getInstallDir() . '/install/updatesql.php'; ob_end_flush(); - return self::SUCCCESS; + return self::SUCCESS; } private function cleanUpdateOutput($buffer) diff --git a/lib/Froxlor/Config/ConfigDaemon.php b/lib/Froxlor/Config/ConfigDaemon.php index 0e9cde33..5929a913 100644 --- a/lib/Froxlor/Config/ConfigDaemon.php +++ b/lib/Froxlor/Config/ConfigDaemon.php @@ -127,6 +127,8 @@ class ConfigDaemon if (is_null($this->sqldata_cache)) { // read in sql-data (if exists) if (file_exists(Froxlor::getInstallDir() . "/lib/userdata.inc.php")) { + $sql = []; + $sql_root = []; require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; unset($sql_root); $this->sqldata_cache = $sql; diff --git a/lib/Froxlor/Cron/Http/Apache.php b/lib/Froxlor/Cron/Http/Apache.php index ad79ed88..18a75547 100644 --- a/lib/Froxlor/Cron/Http/Apache.php +++ b/lib/Froxlor/Cron/Http/Apache.php @@ -40,16 +40,10 @@ use Froxlor\Validate\Validate; use Froxlor\System\Crypt; use PDO; -/** - * @author Florian Lippert (2003-2009) - * @author Froxlor team (2010-) - */ class Apache extends HttpConfigBase { // protected - protected $known_vhostfilenames = []; - protected $known_diroptionsfilenames = []; protected $known_htpasswdsfilenames = []; @@ -1460,8 +1454,6 @@ class Apache extends HttpConfigBase // Write a single file for every vhost foreach ($this->virtualhosts_data as $vhosts_filename => $vhosts_file) { - $this->known_vhostfilenames[] = basename($vhosts_filename); - // Apply header $vhosts_file = '# ' . basename($vhosts_filename) . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n" . "\n" . $vhosts_file; $vhosts_file_handler = fopen($vhosts_filename, 'w'); diff --git a/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php b/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php index b1d78fda..c8cebeaf 100644 --- a/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php +++ b/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php @@ -65,10 +65,10 @@ class AcmeSh extends FroxlorCron /** * run the task * - * @param boolean $internal + * @param bool $internal * @return number */ - public static function run($internal = false) + public static function run(bool $internal = false) { // usually, this is action is called from within the tasks-jobs if (!defined('CRON_IS_FORCED') && !defined('CRON_DEBUG_FLAG') && $internal == false) { @@ -201,6 +201,7 @@ class AcmeSh extends FroxlorCron } else { FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "No new certificates or certificate updates found"); } + return 0; } /** diff --git a/lib/Froxlor/Cron/Http/Lighttpd.php b/lib/Froxlor/Cron/Http/Lighttpd.php index 660113cd..e0e498e8 100644 --- a/lib/Froxlor/Cron/Http/Lighttpd.php +++ b/lib/Froxlor/Cron/Http/Lighttpd.php @@ -29,6 +29,7 @@ use Froxlor\Cron\Http\Php\PhpInterface; use Froxlor\Customer\Customer; use Froxlor\Database\Database; use Froxlor\Domain\Domain; +use Froxlor\Froxlor; use Froxlor\FileDir; use Froxlor\FroxlorLogger; use Froxlor\Http\Directory; @@ -36,14 +37,9 @@ use Froxlor\Http\Statistics; use Froxlor\Settings; use Froxlor\Validate\Validate; use Froxlor\System\Crypt; +use Froxlor\Idna\IdnaWrapper; use PDO; -/** - * @author Florian Lippert (2003-2009) - * @author Froxlor team (2010-) - * - * @todo ssl-redirect to non-standard port - */ class Lighttpd extends HttpConfigBase { @@ -81,7 +77,7 @@ class Lighttpd extends HttpConfigBase $ipv6 = ''; } - $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'lighttpd::createIpPort: creating ip/port settings for ' . $ip . ":" . $port); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'lighttpd::createIpPort: creating ip/port settings for ' . $ip . ":" . $port); $vhost_filename = FileDir::makeCorrectFile(Settings::Get('system.apacheconf_vhost') . '/10_froxlor_ipandport_' . trim(str_replace(':', '.', $row_ipsandports['ip']), '.') . '.' . $row_ipsandports['port'] . '.conf'); if (!isset($this->lighttpd_data[$vhost_filename])) { @@ -126,13 +122,13 @@ class Lighttpd extends HttpConfigBase if (!$is_redirect) { // protect lib/userdata.inc.php - $this->lighttpd_data[$vhosts_filename] .= ' $HTTP["host"] =~ "' . rtrim(Froxlor::getInstallDir(), "/") . '/lib" {' . "\n"; - $this->lighttpd_data[$vhosts_filename] .= ' url.access-deny = ("userdata.inc.php")' . "\n"; - $this->lighttpd_data[$vhosts_filename] .= ' }' . "\n"; + $this->lighttpd_data[$vhost_filename] .= ' $HTTP["host"] =~ "' . rtrim(Froxlor::getInstallDir(), "/") . '/lib" {' . "\n"; + $this->lighttpd_data[$vhost_filename] .= ' url.access-deny = ("userdata.inc.php")' . "\n"; + $this->lighttpd_data[$vhost_filename] .= ' }' . "\n"; // protect bin/ - $this->lighttpd_data[$vhosts_filename] .= ' $HTTP["host"] =~ "' . rtrim(Froxlor::getInstallDir(), "/") . '/bin" {' . "\n"; - $this->lighttpd_data[$vhosts_filename] .= ' url.access-deny = ("")' . "\n"; - $this->lighttpd_data[$vhosts_filename] .= ' }' . "\n"; + $this->lighttpd_data[$vhost_filename] .= ' $HTTP["host"] =~ "' . rtrim(Froxlor::getInstallDir(), "/") . '/bin" {' . "\n"; + $this->lighttpd_data[$vhost_filename] .= ' url.access-deny = ("")' . "\n"; + $this->lighttpd_data[$vhost_filename] .= ' }' . "\n"; /** * dirprotection, see #72 @@ -222,7 +218,7 @@ class Lighttpd extends HttpConfigBase if (($row_ipsandports['ssl_cert_file'] == '' || !file_exists($row_ipsandports['ssl_cert_file'])) && (Settings::Get('system.le_froxlor_enabled') == '0' || $this->froxlorVhostHasLetsEncryptCert() == false)) { $row_ipsandports['ssl_cert_file'] = Settings::Get('system.ssl_cert_file'); if (!file_exists($row_ipsandports['ssl_cert_file'])) { - $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'System certificate file "' . Settings::Get('system.ssl_cert_file') . '" does not seem to exist. Creating self-signed certificate...'); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'System certificate file "' . Settings::Get('system.ssl_cert_file') . '" does not seem to exist. Creating self-signed certificate...'); Crypt::createSelfSignedCertificate(); } } @@ -264,7 +260,7 @@ class Lighttpd extends HttpConfigBase if ($domain['ssl_cert_file'] != '') { // check for existence, #1485 if (!file_exists($domain['ssl_cert_file'])) { - $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, $ip . ':' . $port . ' :: certificate file "' . $domain['ssl_cert_file'] . '" does not exist! Cannot create ssl-directives'); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, $ip . ':' . $port . ' :: certificate file "' . $domain['ssl_cert_file'] . '" does not exist! Cannot create ssl-directives'); echo $ip . ':' . $port . ' :: certificate file "' . $domain['ssl_cert_file'] . '" does not exist! Cannot create SSL-directives' . "\n"; } else { $this->lighttpd_data[$vhost_filename] .= 'ssl.engine = "enable"' . "\n"; @@ -286,7 +282,7 @@ class Lighttpd extends HttpConfigBase if ($domain['ssl_ca_file'] != '') { // check for existence, #1485 if (!file_exists($domain['ssl_ca_file'])) { - $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, $ip . ':' . $port . ' :: certificate CA file "' . $domain['ssl_ca_file'] . '" does not exist! Cannot create ssl-directives'); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, $ip . ':' . $port . ' :: certificate CA file "' . $domain['ssl_ca_file'] . '" does not exist! Cannot create ssl-directives'); echo $ip . ':' . $port . ' :: certificate CA file "' . $domain['ssl_ca_file'] . '" does not exist! SSL-directives might not be working' . "\n"; } else { $this->lighttpd_data[$vhost_filename] .= 'ssl.ca-file = "' . FileDir::makeCorrectFile($domain['ssl_ca_file']) . '"' . "\n"; @@ -571,21 +567,19 @@ class Lighttpd extends HttpConfigBase $this->deactivated = true; } else { if ($ssl === false && $domain['ssl_redirect'] == '1') { - $redirect_domain = $this->idnaConvert->encode('https://' . $domain['domain']); - $webroot_text .= ' url.redirect = (' . "\n"; - $webroot_text .= "\t" . '"^/(.*)" => "' . $redirect_domain . '/$1",' . "\n"; - $webroot_text .= "\t" . '"" => "' . $redirect_domain . '",' . "\n"; - $webroot_text .= "\t" . '"/" => "' . $redirect_domain . '"' . "\n"; - $webroot_text .= ' )' . "\n"; + $redirect_domain = (new IdnaWrapper)->encode('https://' . $domain['domain']); } elseif (preg_match("#^https?://#i", $domain['documentroot'])) { - $redirect_domain = $this->idnaConvert->encode($domain['documentroot']); - $webroot_text .= ' url.redirect = (' . "\n"; - $webroot_text .= "\t" . '"^/(.*)" => "' . $redirect_domain . '/$1",' . "\n"; - $webroot_text .= "\t" . '"" => "' . $redirect_domain . '",' . "\n"; - $webroot_text .= "\t" . '"/" => "' . $redirect_domain . '"' . "\n"; - $webroot_text .= ' )' . "\n"; + $redirect_domain = (new IdnaWrapper)->encode($domain['documentroot']); } else { $webroot_text .= ' server.document-root = "' . FileDir::makeCorrectDir($domain['documentroot']) . "\"\n"; + $redirect_domain = ''; + } + if (!empty($redirect_domain)) { + $webroot_text .= ' url.redirect = (' . "\n"; + $webroot_text .= "\t" . '"^/(.*)" => "' . $redirect_domain . '/$1",' . "\n"; + $webroot_text .= "\t" . '"" => "' . $redirect_domain . '",' . "\n"; + $webroot_text .= "\t" . '"/" => "' . $redirect_domain . '"' . "\n"; + $webroot_text .= ' )' . "\n"; } $this->deactivated = false; } @@ -765,7 +759,7 @@ class Lighttpd extends HttpConfigBase if (!file_exists($domain['ssl_cert_file'])) { // explicitly disable ssl for this vhost $domain['ssl_cert_file'] = ""; - $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'System certificate file "' . Settings::Get('system.ssl_cert_file') . '" does not seem to exist. Disabling SSL-vhost for "' . $domain['domain'] . '"'); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'System certificate file "' . Settings::Get('system.ssl_cert_file') . '" does not seem to exist. Disabling SSL-vhost for "' . $domain['domain'] . '"'); } } @@ -923,7 +917,7 @@ class Lighttpd extends HttpConfigBase public function writeConfigs() { - $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "lighttpd::writeConfigs: rebuilding " . Settings::Get('system.apacheconf_vhost')); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "lighttpd::writeConfigs: rebuilding " . Settings::Get('system.apacheconf_vhost')); $vhostDir = new Directory(Settings::Get('system.apacheconf_vhost')); if (!$vhostDir->isConfigDir()) { @@ -950,14 +944,12 @@ class Lighttpd extends HttpConfigBase fclose($vhosts_file_handler); } else { if (!file_exists(Settings::Get('system.apacheconf_vhost'))) { - $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'lighttpd::writeConfigs: mkdir ' . escapeshellarg(FileDir::makeCorrectDir(Settings::Get('system.apacheconf_vhost')))); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'lighttpd::writeConfigs: mkdir ' . escapeshellarg(FileDir::makeCorrectDir(Settings::Get('system.apacheconf_vhost')))); FileDir::safe_exec('mkdir ' . escapeshellarg(FileDir::makeCorrectDir(Settings::Get('system.apacheconf_vhost')))); } // Write a single file for every vhost foreach ($this->lighttpd_data as $vhosts_filename => $vhosts_file) { - $this->known_filenames[] = basename($vhosts_filename); - // Apply header $vhosts_file = '# ' . basename($vhosts_filename) . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n" . "\n" . $vhosts_file; diff --git a/lib/Froxlor/Cron/Http/Nginx.php b/lib/Froxlor/Cron/Http/Nginx.php index a0c9c1bb..1de54bf3 100644 --- a/lib/Froxlor/Cron/Http/Nginx.php +++ b/lib/Froxlor/Cron/Http/Nginx.php @@ -29,6 +29,7 @@ use Froxlor\Cron\Http\Php\PhpInterface; use Froxlor\Customer\Customer; use Froxlor\Database\Database; use Froxlor\Domain\Domain; +use Froxlor\Froxlor; use Froxlor\FileDir; use Froxlor\FroxlorLogger; use Froxlor\Http\Directory; @@ -50,8 +51,7 @@ class Nginx extends HttpConfigBase protected $known_htpasswdsfilenames = []; protected $mod_accesslog_loaded = '0'; protected $vhost_root_autoindex = false; - protected $known_vhostfilenames = []; - private $nginx_server = []; + /** * indicator whether a customer is deactivated or not * if yes, only the webroot will be generated @@ -60,11 +60,6 @@ class Nginx extends HttpConfigBase */ private $deactivated = false; - public function __construct($nginx_server = []) - { - $this->nginx_server = $nginx_server; - } - public function createVirtualHosts() { return; @@ -220,14 +215,14 @@ class Nginx extends HttpConfigBase $this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n"; // protect lib/userdata.inc.php - $this->nginx_data[$vhosts_filename] .= "\t" . 'location = ' . rtrim(Froxlor::getInstallDir(), "/") . '/lib/userdata.inc.php {' . "\n"; - $this->nginx_data[$vhosts_filename] .= "\t" . ' deny all;' . "\n"; - $this->nginx_data[$vhosts_filename] .= "\t" . '}' . "\n"; + $this->nginx_data[$vhost_filename] .= "\t" . 'location = ' . rtrim(Froxlor::getInstallDir(), "/") . '/lib/userdata.inc.php {' . "\n"; + $this->nginx_data[$vhost_filename] .= "\t" . ' deny all;' . "\n"; + $this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n"; // protect bin/ - $this->nginx_data[$vhosts_filename] .= "\t" . 'location = ' . rtrim(Froxlor::getInstallDir(), "/") . '/bin {' . "\n"; - $this->nginx_data[$vhosts_filename] .= "\t" . ' deny all;' . "\n"; - $this->nginx_data[$vhosts_filename] .= "\t" . '}' . "\n"; + $this->nginx_data[$vhost_filename] .= "\t" . 'location = ' . rtrim(Froxlor::getInstallDir(), "/") . '/bin {' . "\n"; + $this->nginx_data[$vhost_filename] .= "\t" . ' deny all;' . "\n"; + $this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n"; } if ($row_ipsandports['specialsettings'] != '' && ($row_ipsandports['ssl'] == '0' || ($row_ipsandports['ssl'] == '1' && Settings::Get('system.use_ssl') == '1' && $row_ipsandports['include_specialsettings'] == '1'))) { @@ -1252,8 +1247,6 @@ class Nginx extends HttpConfigBase // Write a single file for every vhost foreach ($this->nginx_data as $vhosts_filename => $vhosts_file) { - $this->known_filenames[] = basename($vhosts_filename); - // Apply header $vhosts_file = '# ' . basename($vhosts_filename) . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n" . "\n" . $vhosts_file; diff --git a/lib/Froxlor/Cron/Http/Php/PhpInterface.php b/lib/Froxlor/Cron/Http/Php/PhpInterface.php index 015fe978..a356d2f6 100644 --- a/lib/Froxlor/Cron/Http/Php/PhpInterface.php +++ b/lib/Froxlor/Cron/Http/Php/PhpInterface.php @@ -46,11 +46,11 @@ class PhpInterface private $interface = null; /** - * Admin-User data array + * PHP-Config data array * * @var array */ - private $admin_cache = []; + private $php_configs_cache = []; /** * main constructor @@ -93,10 +93,8 @@ class PhpInterface * * @return array */ - public function getPhpConfig($php_config_id) + public function getPhpConfig(int $php_config_id) { - $php_config_id = intval($php_config_id); - // If domain has no config, we will use the default one. if ($php_config_id == 0) { $php_config_id = 1; @@ -104,24 +102,26 @@ class PhpInterface if (!isset($this->php_configs_cache[$php_config_id])) { $stmt = Database::prepare(" - SELECT * FROM `" . TABLE_PANEL_PHPCONFIGS . "` WHERE `id` = :id"); - $this->_php_configs_cache[$php_config_id] = Database::pexecute_first($stmt, [ + SELECT * FROM `" . TABLE_PANEL_PHPCONFIGS . "` WHERE `id` = :id + "); + $this->php_configs_cache[$php_config_id] = Database::pexecute_first($stmt, [ 'id' => $php_config_id ]); if ((int)Settings::Get('phpfpm.enabled') == 1) { $stmt = Database::prepare(" - SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "` WHERE `id` = :id"); - $this->_php_configs_cache[$php_config_id]['fpm_settings'] = Database::pexecute_first($stmt, [ - 'id' => $this->_php_configs_cache[$php_config_id]['fpmsettingid'] + SELECT * FROM `" . TABLE_PANEL_FPMDAEMONS . "` WHERE `id` = :id + "); + $this->php_configs_cache[$php_config_id]['fpm_settings'] = Database::pexecute_first($stmt, [ + 'id' => $this->php_configs_cache[$php_config_id]['fpmsettingid'] ]); // override fpm daemon settings if set in php-config - if ($this->_php_configs_cache[$php_config_id]['override_fpmconfig'] == 1) { - $this->_php_configs_cache[$php_config_id]['fpm_settings']['limit_extensions'] = $this->_php_configs_cache[$php_config_id]['limit_extensions']; - $this->_php_configs_cache[$php_config_id]['fpm_settings']['idle_timeout'] = $this->_php_configs_cache[$php_config_id]['idle_timeout']; + if ($this->php_configs_cache[$php_config_id]['override_fpmconfig'] == 1) { + $this->php_configs_cache[$php_config_id]['fpm_settings']['limit_extensions'] = $this->php_configs_cache[$php_config_id]['limit_extensions']; + $this->php_configs_cache[$php_config_id]['fpm_settings']['idle_timeout'] = $this->php_configs_cache[$php_config_id]['idle_timeout']; } } } - return $this->_php_configs_cache[$php_config_id]; + return $this->php_configs_cache[$php_config_id]; } } diff --git a/lib/Froxlor/Database/Database.php b/lib/Froxlor/Database/Database.php index 70fe03db..7f0a2754 100644 --- a/lib/Froxlor/Database/Database.php +++ b/lib/Froxlor/Database/Database.php @@ -127,6 +127,9 @@ class Database { global $userinfo, $theme, $linker; + $sql = []; + $sql_root = []; + // include userdata.inc.php require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; diff --git a/lib/Froxlor/FileDir.php b/lib/Froxlor/FileDir.php index 2c5538fb..ed61b2ac 100644 --- a/lib/Froxlor/FileDir.php +++ b/lib/Froxlor/FileDir.php @@ -26,12 +26,10 @@ namespace Froxlor; use Exception; -use Froxlor\Customer\Customer; -use Froxlor\Database\Database; use PDO; use RecursiveCallbackFilterIterator; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; +use Froxlor\Customer\Customer; +use Froxlor\Database\Database; class FileDir { @@ -550,12 +548,11 @@ class FileDir /** * set the immutable flag for a file * - * @param string $filename - * the file to set the flag for + * @param string $filename the file to set the flag for * - * @return boolean + * @return void */ - public static function setImmutable($filename = null) + public static function setImmutable(string $filename) { FileDir::safe_exec(self::getImmutableFunction(false) . escapeshellarg($filename)); } @@ -564,12 +561,11 @@ class FileDir * internal function to check whether * to use chattr (Linux) or chflags (FreeBSD) * - * @param boolean $remove - * whether to use +i|schg (false) or -i|noschg (true) + * @param bool $remove whether to use +i|schg (false) or -i|noschg (true) * * @return string functionname + parameter (not the file) */ - private static function getImmutableFunction($remove = false) + private static function getImmutableFunction(bool $remove = false) { if (self::isFreeBSD()) { // FreeBSD style @@ -585,12 +581,11 @@ class FileDir * or BSD-based (NetBSD, OpenBSD, etc. * if exact = false [default]) * - * @param boolean $exact - * whether to check explicitly for FreeBSD or *BSD + * @param bool $exact whether to check explicitly for FreeBSD or *BSD * - * @return boolean + * @return bool */ - public static function isFreeBSD($exact = false) + public static function isFreeBSD(bool $exact = false) { if (($exact && PHP_OS == 'FreeBSD') || (!$exact && stristr(PHP_OS, 'BSD'))) { return true; @@ -601,16 +596,19 @@ class FileDir /** * removes the immutable flag for a file * - * @param string $filename - * the file to set the flag for + * @param string $filename the file to set the flag for * - * @return boolean + * @return void */ - public static function removeImmutable($filename = null) + public static function removeImmutable(string $filename) { FileDir::safe_exec(self::getImmutableFunction(true) . escapeshellarg($filename)); } + /** + * + * @return array|false + */ public static function getFilesystemQuota() { // enabled at all? diff --git a/lib/Froxlor/Install/AutoUpdate.php b/lib/Froxlor/Install/AutoUpdate.php index 6b3fdcf7..ce896b89 100644 --- a/lib/Froxlor/Install/AutoUpdate.php +++ b/lib/Froxlor/Install/AutoUpdate.php @@ -26,6 +26,7 @@ namespace Froxlor\Install; use Exception; +use ZipArchive; use Froxlor\Froxlor; use Froxlor\Settings; use Froxlor\Http\HttpClient; diff --git a/lib/Froxlor/Install/Update.php b/lib/Froxlor/Install/Update.php index c1c21584..18914a0f 100644 --- a/lib/Froxlor/Install/Update.php +++ b/lib/Froxlor/Install/Update.php @@ -31,6 +31,9 @@ use Froxlor\Settings; class Update { + private static $update_tasks = []; + + private static $task_counter = 0; /** * Function showUpdateStep @@ -42,20 +45,18 @@ class Update * * @return void */ - public static function showUpdateStep($task = null, $needs_status = true) + public static function showUpdateStep(string $task, bool $needs_status = true) { - global $update_tasks, $task_counter; - set_time_limit(30); // output - $update_tasks[$task_counter] = ['title' => $task, 'result' => 0]; + self::$update_tasks[self::$task_counter] = ['title' => $task, 'result' => 0]; if (!$needs_status) { - $task_counter++; + self::$task_counter++; } - FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, $task); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::ADM_ACTION, \LOG_WARNING, $task); } /** @@ -67,35 +68,33 @@ class Update * @param string $message * @param string $additional_info * - * @return string formatted output and log-entry + * @return void */ public static function lastStepStatus(int $status = -1, string $message = '', string $additional_info = '') { - global $update_tasks, $task_counter; - - $update_tasks[$task_counter]['result_txt'] = $message ?? 'OK'; - $update_tasks[$task_counter]['result_desc'] = $additional_info ?? ''; + self::$update_tasks[self::$task_counter]['result_txt'] = $message ?? 'OK'; + self::$update_tasks[self::$task_counter]['result_desc'] = $additional_info ?? ''; switch ($status) { case 0: break; case 1: - $update_tasks[$task_counter]['result'] = 2; + self::$update_tasks[self::$task_counter]['result'] = 2; break; case 2: - $update_tasks[$task_counter]['result'] = 1; + self::$update_tasks[self::$task_counter]['result'] = 1; break; default: - $update_tasks[$task_counter]['result'] = -1; + self::$update_tasks[self::$task_counter]['result'] = -1; break; } - $task_counter++; + self::$task_counter++; if ($status == -1 || $status == 2) { - FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, 'Attention - last update task failed!!!'); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::ADM_ACTION, \LOG_WARNING, 'Attention - last update task failed!!!'); } elseif ($status == 0 || $status == 1) { - FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, 'Success'); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::ADM_ACTION, \LOG_WARNING, 'Success'); } } @@ -127,4 +126,14 @@ class Update } return null; } + + public static function getUpdateTasks(): array + { + return self::$update_tasks; + } + + public static function getTaskCounter(): int + { + return self::$task_counter; + } } diff --git a/lib/Froxlor/UI/Listing.php b/lib/Froxlor/UI/Listing.php index d124b5aa..6403b4d4 100644 --- a/lib/Froxlor/UI/Listing.php +++ b/lib/Froxlor/UI/Listing.php @@ -60,7 +60,6 @@ class Listing { return [ 'title' => $tabellisting['title'], - 'icon' => $tabellisting['icon'], 'description' => $tabellisting['description'] ?? null, 'icon' => $tabellisting['icon'] ?? null, 'table' => [ diff --git a/lib/Froxlor/Validate/Validate.php b/lib/Froxlor/Validate/Validate.php index dc0a44e6..339c2ca0 100644 --- a/lib/Froxlor/Validate/Validate.php +++ b/lib/Froxlor/Validate/Validate.php @@ -46,23 +46,19 @@ class Validate const REGEX_YYYY_MM_DD = '/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/'; /** - * Validates the given string by matching against the pattern, prints an error on failure and exits + * Validates the given string by matching against the pattern, prints an error on failure and exits. + * If the default pattern is used and the string does not match, we try to replace the 'bad' values and log the action. * - * @param string $str - * the string to be tested (user input) - * @param - * string the $fieldname to be used in error messages - * @param string $pattern - * the regular expression to be used for testing - * @param - * string language id for the error - * @return string the clean string - * - * If the default pattern is used and the string does not match, we try to replace the - * 'bad' values and log the action. + * @param string $str the string to be tested (user input) + * @param string $fieldname to be used in error messages + * @param string $pattern the regular expression to be used for testing + * @param string $language id for the error + * @param string|array $emptydefault fallback value + * @param bool $throw_exception whether to display error or throw an exception, default false * + * @return string|void the clean string or error */ - public static function validate($str, $fieldname, $pattern = '', $lng = '', $emptydefault = [], $throw_exception = false) + public static function validate($str, string $fieldname, string $pattern = '', string $lng = '', $emptydefault = [], bool $throw_exception = false) { if (!is_array($emptydefault)) { $emptydefault_array = [ @@ -122,9 +118,9 @@ class Validate * @param bool $throw_exception * whether to throw an exception on failure * - * @return string|bool ip address on success, false on failure + * @return string|bool|void ip address on success, false on failure (or nothing if error is displayed) */ - public static function validate_ip2($ip, $return_bool = false, $lng = 'invalidip', $allow_localhost = false, $allow_priv = false, $allow_cidr = false, $cidr_as_netmask = false, $throw_exception = false) + public static function validate_ip2($ip, bool $return_bool = false, string $lng = 'invalidip', bool $allow_localhost = false, bool $allow_priv = false, bool $allow_cidr = false, bool $cidr_as_netmask = false, bool $throw_exception = false) { $cidr = ""; if ($allow_cidr) { @@ -136,15 +132,17 @@ class Validate $cidr_range_max = 128; } if (strlen($ip_cidr[1]) <= 3 && in_array((int)$ip_cidr[1], array_values(range(1, $cidr_range_max)), true) === false) { + if ($return_bool) { + return false; + } Response::standardError($lng, $ip, $throw_exception); } if ($cidr_as_netmask && IPTools::is_ipv6($ip_cidr[0])) { // MySQL does not handle CIDR of IPv6 addresses, return error if ($return_bool) { return false; - } else { - Response::standardError($lng, $ip, $throw_exception); } + Response::standardError($lng, $ip, $throw_exception); } $ip = $ip_cidr[0]; if ($cidr_as_netmask && strlen($ip_cidr[1]) <= 3) { @@ -157,9 +155,8 @@ class Validate } elseif (strpos($ip, "/") !== false) { if ($return_bool) { return false; - } else { - Response::standardError($lng, $ip, $throw_exception); } + Response::standardError($lng, $ip, $throw_exception); } $filter_lan = $allow_priv ? FILTER_FLAG_NO_RES_RANGE : (FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE); @@ -175,9 +172,8 @@ class Validate if ($return_bool) { return false; - } else { - Response::standardError($lng, $ip, $throw_exception); } + Response::standardError($lng, $ip, $throw_exception); } /** From 16a9b18dad0a51c699bdb32899dd4f4898b8d2cc Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 10 Aug 2022 11:06:38 +0200 Subject: [PATCH 03/11] fix type of parameter in Validate::validate() Signed-off-by: Michael Kaufmann --- lib/Froxlor/Validate/Validate.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Froxlor/Validate/Validate.php b/lib/Froxlor/Validate/Validate.php index 339c2ca0..70d588e6 100644 --- a/lib/Froxlor/Validate/Validate.php +++ b/lib/Froxlor/Validate/Validate.php @@ -52,13 +52,13 @@ class Validate * @param string $str the string to be tested (user input) * @param string $fieldname to be used in error messages * @param string $pattern the regular expression to be used for testing - * @param string $language id for the error + * @param string|array $lng id for the error * @param string|array $emptydefault fallback value * @param bool $throw_exception whether to display error or throw an exception, default false * * @return string|void the clean string or error */ - public static function validate($str, string $fieldname, string $pattern = '', string $lng = '', $emptydefault = [], bool $throw_exception = false) + public static function validate($str, string $fieldname, string $pattern = '', $lng = '', $emptydefault = [], bool $throw_exception = false) { if (!is_array($emptydefault)) { $emptydefault_array = [ From e82d7b5d8bc657e89f29d9d149ac9a03ae9d8fff Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 10 Aug 2022 11:15:06 +0200 Subject: [PATCH 04/11] add missing namespaces, fix typo Signed-off-by: Michael Kaufmann --- install/updates/froxlor/update_0.10.inc.php | 6 ++++-- install/updates/froxlor/update_0.11.inc.php | 2 +- lib/Froxlor/FileDir.php | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/install/updates/froxlor/update_0.10.inc.php b/install/updates/froxlor/update_0.10.inc.php index f9374aff..d7ef1450 100644 --- a/install/updates/froxlor/update_0.10.inc.php +++ b/install/updates/froxlor/update_0.10.inc.php @@ -24,10 +24,12 @@ */ use Froxlor\Froxlor; +use Froxlor\FileDir; use Froxlor\Database\Database; use Froxlor\Settings; use Froxlor\Install\Update; use Froxlor\System\Cronjob; +use Froxlor\System\IPTools; if (!defined('_CRON_UPDATE')) { if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) { @@ -323,7 +325,7 @@ if (Froxlor::isDatabaseVersion('201907270')) { $complete_filedir = Froxlor::getInstallDir() . $filedir; if (file_exists($complete_filedir)) { if ($exec_allowed) { - Froxlor\FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir)); + FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir)); } else { $del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL; } @@ -889,7 +891,7 @@ if (Froxlor::isDatabaseVersion('202107210')) { Database::pexecute($result_stmt); $upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_IPSANDPORTS . "` SET `ip` = :ip WHERE `id` = :id"); while ($iprow = $result_stmt->fetch(\PDO::FETCH_ASSOC)) { - if (Validate::is_ipv6($iprow['ip'])) { + if (IPTools::is_ipv6($iprow['ip'])) { $ip = inet_ntop(inet_pton($iprow['ip'])); Database::pexecute($upd_stmt, [ 'ip' => $ip, diff --git a/install/updates/froxlor/update_0.11.inc.php b/install/updates/froxlor/update_0.11.inc.php index d4454423..8da662a0 100644 --- a/install/updates/froxlor/update_0.11.inc.php +++ b/install/updates/froxlor/update_0.11.inc.php @@ -79,7 +79,7 @@ if (Froxlor::isFroxlorVersion('0.10.99')) { "); $upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `allowed_mysqlserver` = :allowed_mysqlserver WHERE `customerid` = :customerid"); while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) { - if (isset($dbserver['allowed_mysqlserver']) && !empt($dbserver['allowed_mysqlserver'])) { + if (isset($dbserver['allowed_mysqlserver']) && !empty($dbserver['allowed_mysqlserver'])) { $allowed_mysqlserver = json_encode(explode(",", $dbserver['allowed_mysqlserver'])); Database::pexecute($upd_stmt, ['allowed_mysql_server' => $allowed_mysqlserver, 'customerid' => $dbserver['customerid']]); } diff --git a/lib/Froxlor/FileDir.php b/lib/Froxlor/FileDir.php index ed61b2ac..f1f68c6f 100644 --- a/lib/Froxlor/FileDir.php +++ b/lib/Froxlor/FileDir.php @@ -554,7 +554,7 @@ class FileDir */ public static function setImmutable(string $filename) { - FileDir::safe_exec(self::getImmutableFunction(false) . escapeshellarg($filename)); + self::safe_exec(self::getImmutableFunction(false) . escapeshellarg($filename)); } /** From 94a19ee2b696bdfeedf68259272246e91872aa46 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 10 Aug 2022 12:01:26 +0200 Subject: [PATCH 05/11] more minor fixes and code-cleaning Signed-off-by: Michael Kaufmann --- index.php | 2 +- install/updates/froxlor/update_0.10.inc.php | 10 +++++----- lib/Froxlor/Api/Commands/MysqlServer.php | 6 ++++-- lib/Froxlor/Api/Commands/Mysqls.php | 2 +- lib/Froxlor/Config/ConfigDisplay.php | 2 +- lib/Froxlor/Cron/System/TasksCron.php | 3 ++- lib/Froxlor/Database/Database.php | 7 ++++--- lib/Froxlor/FileDir.php | 4 ++-- lib/Froxlor/Froxlor.php | 4 ++-- lib/Froxlor/Install/Install.php | 2 +- lib/Froxlor/Install/Update.php | 6 +++--- lib/Froxlor/PhpHelper.php | 4 ++-- lib/Froxlor/System/Mailer.php | 4 ++-- lib/Froxlor/UI/Listing.php | 2 +- lib/Froxlor/UI/Panel/UI.php | 2 +- lib/init.php | 2 +- 16 files changed, 33 insertions(+), 29 deletions(-) diff --git a/index.php b/index.php index 7a77ecb8..f8c60f63 100644 --- a/index.php +++ b/index.php @@ -411,7 +411,7 @@ if ($action == 'forgotpwd') { if (isset($_POST['send']) && $_POST['send'] == 'send') { $loginname = Validate::validate($_POST['loginname'], 'loginname'); - $email = Validate::validateEmail($_POST['loginemail'], 'email'); + $email = Validate::validateEmail($_POST['loginemail']); $result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `loginname`= :loginname AND `email`= :email"); diff --git a/install/updates/froxlor/update_0.10.inc.php b/install/updates/froxlor/update_0.10.inc.php index d7ef1450..9797f174 100644 --- a/install/updates/froxlor/update_0.10.inc.php +++ b/install/updates/froxlor/update_0.10.inc.php @@ -98,7 +98,7 @@ if (Froxlor::isDatabaseVersion('201809280')) { if (Froxlor::isDatabaseVersion('201811180')) { Update::showUpdateStep("Adding new settings for 2FA"); - Settings::AddNew('2fa.enabled', '1', true); + Settings::AddNew('2fa.enabled', '1'); Update::lastStepStatus(0); Update::showUpdateStep("Adding new fields to admin-table for 2FA"); @@ -127,7 +127,7 @@ if (Froxlor::isDatabaseVersion('201812010')) { Update::showUpdateStep("Adding new is_configured-flag"); // updated systems are already configured (most likely :P) - Settings::AddNew('panel.is_configured', '1', true); + Settings::AddNew('panel.is_configured', '1'); Update::lastStepStatus(0); Froxlor::updateToDbVersion('201812100'); @@ -287,8 +287,8 @@ if (Froxlor::isFroxlorVersion('0.10.0-rc1')) { if (Froxlor::isDatabaseVersion('201904250')) { Update::showUpdateStep("Adding new settings for CAA"); - Settings::AddNew('caa.caa_entry', '', true); - Settings::AddNew('system.dns_createcaaentry', 1, true); + Settings::AddNew('caa.caa_entry', ''); + Settings::AddNew('system.dns_createcaaentry', 1); Update::lastStepStatus(0); Froxlor::updateToDbVersion('201907270'); @@ -928,7 +928,7 @@ if (Froxlor::isFroxlorVersion('0.10.27')) { if (Froxlor::isDatabaseVersion('202108180')) { Update::showUpdateStep("Adding czech language file", true); - Database::query("INSERT INTO `" . TABLE_PANEL_LANGUAGE . "` SET `language` = 'Česká republika', `iso` = 'cs', `file` = 'lng/czech.lng.php'"); + Database::query("INSERT INTO `panel_languages` SET `language` = 'Česká republika', `iso` = 'cs', `file` = 'lng/czech.lng.php'"); Update::lastStepStatus(0); Froxlor::updateToDbVersion('202109040'); } diff --git a/lib/Froxlor/Api/Commands/MysqlServer.php b/lib/Froxlor/Api/Commands/MysqlServer.php index 89f15c50..72ee0f92 100644 --- a/lib/Froxlor/Api/Commands/MysqlServer.php +++ b/lib/Froxlor/Api/Commands/MysqlServer.php @@ -131,7 +131,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; // le format - if (isset($sql['root_user']) && isset($sql['root_password']) && (!isset($sql_root) || !is_array($sql_root))) { + if (isset($sql['root_user']) && isset($sql['root_password']) &&!is_array($sql_root)) { $sql_root = array( 0 => array( 'caption' => 'Default', @@ -154,7 +154,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity 'password' => $privileged_password, 'ssl' => [ 'caFile' => $mysql_ca ?? "", - 'verifyServerCertificate' => $mysql_verifycert ?? false + 'verifyServerCertificate' => $mysql_verifycert ] ]; @@ -195,6 +195,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity throw new Exception('Cannot delete first/default mysql-server', 406); } + $sql_root = []; // get all data from lib/userdata require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; @@ -358,6 +359,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity $dbserver = (int) $this->getParam('dbserver', $dn_optional, -1); $dbserver = $id >= 0 ? $id : $dbserver; + $sql_root = []; require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; if (!isset($sql_root[$dbserver])) { diff --git a/lib/Froxlor/Api/Commands/Mysqls.php b/lib/Froxlor/Api/Commands/Mysqls.php index 0708077f..6731a027 100644 --- a/lib/Froxlor/Api/Commands/Mysqls.php +++ b/lib/Froxlor/Api/Commands/Mysqls.php @@ -94,7 +94,7 @@ class Mysqls extends ApiCommand implements ResourceEntity Database::needSqlData(); $sql_root = Database::getSqlData(); Database::needRoot(false); - if (!isset($sql_root) || !is_array($sql_root)) { + if (!is_array($sql_root)) { throw new Exception("Database server with index #" . $dbserver . " is unknown", 404); } diff --git a/lib/Froxlor/Config/ConfigDisplay.php b/lib/Froxlor/Config/ConfigDisplay.php index 2ca6862e..558ad409 100644 --- a/lib/Froxlor/Config/ConfigDisplay.php +++ b/lib/Froxlor/Config/ConfigDisplay.php @@ -109,7 +109,7 @@ class ConfigDisplay } } - Database::needSqlData(true); + Database::needSqlData(); $sql = Database::getSqlData(); self::$replace_arr = [ diff --git a/lib/Froxlor/Cron/System/TasksCron.php b/lib/Froxlor/Cron/System/TasksCron.php index 982a4b04..8deff792 100644 --- a/lib/Froxlor/Cron/System/TasksCron.php +++ b/lib/Froxlor/Cron/System/TasksCron.php @@ -27,6 +27,7 @@ namespace Froxlor\Cron\System; use Froxlor\Cron\FroxlorCron; use Froxlor\Cron\Http\ConfigIO; +use Froxlor\Cron\Http\HttpConfigBase; use Froxlor\Cron\TaskId; use Froxlor\Database\Database; use Froxlor\Dns\PowerDNS; @@ -158,7 +159,7 @@ class TasksCron extends FroxlorCron // get webserver object $webserver = new $websrv(); - if (isset($webserver)) { + if ($webserver instanceof HttpConfigBase) { $webserver->init(); // clean up old configs $configio->cleanUp(); diff --git a/lib/Froxlor/Database/Database.php b/lib/Froxlor/Database/Database.php index 7f0a2754..f9e4da12 100644 --- a/lib/Froxlor/Database/Database.php +++ b/lib/Froxlor/Database/Database.php @@ -45,6 +45,7 @@ use PDOStatement; * object * @method static string lastInsertId ($name = null) Returns the ID of the last inserted row or sequence value * @method static string quote ($string, $parameter_type = null) Quotes a string for use in a query. + * @method static mixed getAttribute(int $attribute) Retrieve a database connection attribute */ class Database { @@ -134,7 +135,7 @@ class Database require Froxlor::getInstallDir() . "/lib/userdata.inc.php"; // le format - if (isset($sql['root_user']) && isset($sql['root_password']) && (!isset($sql_root) || !is_array($sql_root))) { + if (isset($sql['root_user']) && isset($sql['root_password']) && !is_array($sql_root)) { $sql_root = [ 0 => [ 'caption' => 'Default', @@ -294,13 +295,13 @@ class Database */ private static function genUniqueToken(int $length = 16) { - if (!isset($length) || intval($length) <= 8) { + if (intval($length) <= 8) { $length = 16; } if (function_exists('random_bytes')) { return bin2hex(random_bytes($length)); } - if (function_exists('mcrypt_create_iv')) { + if (function_exists('mcrypt_create_iv') && defined('MCRYPT_DEV_URANDOM')) { return bin2hex(mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)); } if (function_exists('openssl_random_pseudo_bytes')) { diff --git a/lib/Froxlor/FileDir.php b/lib/Froxlor/FileDir.php index f1f68c6f..98012c97 100644 --- a/lib/Froxlor/FileDir.php +++ b/lib/Froxlor/FileDir.php @@ -313,9 +313,9 @@ class FileDir * * @return string the corrected filename */ - public static function makeCorrectFile($filename) + public static function makeCorrectFile(string $filename) { - if (!isset($filename) || trim($filename) == '') { + if (trim($filename) == '') { $error = 'Given filename for function ' . __FUNCTION__ . ' is empty.' . "\n"; $error .= 'This is very dangerous and should not happen.' . "\n"; $error .= 'Please inform the Froxlor team about this issue so they can fix it.'; diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index f85c6a4e..f51031e0 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -234,13 +234,13 @@ final class Froxlor */ public static function genSessionId(int $length = 16) { - if (!isset($length) || intval($length) <= 8) { + if (intval($length) <= 8) { $length = 16; } if (function_exists('random_bytes')) { return bin2hex(random_bytes($length)); } - if (function_exists('mcrypt_create_iv')) { + if (function_exists('mcrypt_create_iv') && defined('MCRYPT_DEV_URANDOM')) { return bin2hex(mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)); } if (function_exists('openssl_random_pseudo_bytes')) { diff --git a/lib/Froxlor/Install/Install.php b/lib/Froxlor/Install/Install.php index 2dbf19af..07df0261 100644 --- a/lib/Froxlor/Install/Install.php +++ b/lib/Froxlor/Install/Install.php @@ -332,7 +332,7 @@ class Install throw new Exception(lng('error.emailiswrong', [$email])); } elseif (empty($password) || $password != $password_confirm) { throw new Exception(lng('error.newpasswordconfirmerror')); - } elseif (!empty($password) && $password == $loginname) { + } elseif ($password == $loginname) { throw new Exception(lng('error.passwordshouldnotbeusername')); } } diff --git a/lib/Froxlor/Install/Update.php b/lib/Froxlor/Install/Update.php index 18914a0f..1640033f 100644 --- a/lib/Froxlor/Install/Update.php +++ b/lib/Froxlor/Install/Update.php @@ -70,10 +70,10 @@ class Update * * @return void */ - public static function lastStepStatus(int $status = -1, string $message = '', string $additional_info = '') + public static function lastStepStatus(int $status = -1, string $message = 'OK', string $additional_info = '') { - self::$update_tasks[self::$task_counter]['result_txt'] = $message ?? 'OK'; - self::$update_tasks[self::$task_counter]['result_desc'] = $additional_info ?? ''; + self::$update_tasks[self::$task_counter]['result_txt'] = $message; + self::$update_tasks[self::$task_counter]['result_desc'] = $additional_info; switch ($status) { case 0: diff --git a/lib/Froxlor/PhpHelper.php b/lib/Froxlor/PhpHelper.php index d45a6642..adfe9f78 100644 --- a/lib/Froxlor/PhpHelper.php +++ b/lib/Froxlor/PhpHelper.php @@ -458,7 +458,7 @@ class PhpHelper 'ssl_default_vhostconf_domain', 'filecontent' ]; - if (isset($global) && !empty($global)) { + if (!empty($global)) { $tmp = $global; foreach ($tmp as $index => $value) { if (!in_array($index, $ignored_fields)) { @@ -516,7 +516,7 @@ class PhpHelper $str .= self::tabPrefix(($depth-1), "[\n"); } foreach ($array as $key => $value) { - if (isset($key) && !is_array($value)) { + if (!is_array($value)) { if (is_bool($value)) { $str .= self::tabPrefix($depth, sprintf("'%s' => %s,\n", $key, $value ? 'true' : 'false')); } elseif (is_int($value)) { diff --git a/lib/Froxlor/System/Mailer.php b/lib/Froxlor/System/Mailer.php index d91cc5aa..a3b965c4 100644 --- a/lib/Froxlor/System/Mailer.php +++ b/lib/Froxlor/System/Mailer.php @@ -34,11 +34,11 @@ class Mailer extends PHPMailer /** * class constructor * - * @param string $exceptions + * @param bool $exceptions * whether to throw exceptions or not * */ - public function __construct($exceptions = false) + public function __construct(bool $exceptions = false) { parent::__construct($exceptions); $this->CharSet = "UTF-8"; diff --git a/lib/Froxlor/UI/Listing.php b/lib/Froxlor/UI/Listing.php index 6403b4d4..12c9ea20 100644 --- a/lib/Froxlor/UI/Listing.php +++ b/lib/Froxlor/UI/Listing.php @@ -52,7 +52,7 @@ class Listing 'is_search' => $collection->getPagination() instanceof Pagination && $collection->getPagination()->isSearchResult(), 'self_overview' => $tabellisting['self_overview'] ?? [], 'available_columns' => self::getAvailableColumnsForListing($tabellisting), - 'listing_search_additional_param' => $listing_search_additional_param ?? [], + 'listing_search_additional_param' => $listing_search_additional_param, ]; } diff --git a/lib/Froxlor/UI/Panel/UI.php b/lib/Froxlor/UI/Panel/UI.php index 92f45f64..0fc201ef 100644 --- a/lib/Froxlor/UI/Panel/UI.php +++ b/lib/Froxlor/UI/Panel/UI.php @@ -279,7 +279,7 @@ class UI } } if (!file_exists(Froxlor::getInstallDir() . '/templates/' . $theme)) { - PhpHelper::phpErrHandler(E_USER_WARNING, "Theme '" . $theme . "' could not be found.", __FILE__, __LINE__, null); + PhpHelper::phpErrHandler(E_USER_WARNING, "Theme '" . $theme . "' could not be found.", __FILE__, __LINE__); $theme = self::$default_theme; } return $theme; diff --git a/lib/init.php b/lib/init.php index 6e90ff2d..5ec6505d 100644 --- a/lib/init.php +++ b/lib/init.php @@ -223,7 +223,7 @@ if (!CurrentUser::hasSession() && AREA != 'login') { } $userinfo = CurrentUser::getData(); -UI::twig()->addGlobal('userinfo', ($userinfo ?? [])); +UI::twig()->addGlobal('userinfo', $userinfo); UI::setCurrentUser($userinfo); // Initialize logger if (CurrentUser::hasSession()) { From 9dc95e086de496cd19a91e7167a7849edb4fb9ad Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Tue, 16 Aug 2022 08:32:43 +0200 Subject: [PATCH 06/11] correct Dropdown directory selection; fixes #1044 Signed-off-by: Michael Kaufmann --- lib/Froxlor/FileDir.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Froxlor/FileDir.php b/lib/Froxlor/FileDir.php index 98012c97..49c649c1 100644 --- a/lib/Froxlor/FileDir.php +++ b/lib/Froxlor/FileDir.php @@ -525,7 +525,7 @@ class FileDir new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), $filter ), - \RecursiveIteratorIterator::LEAVES_ONLY, + \RecursiveIteratorIterator::SELF_FIRST, \RecursiveIteratorIterator::CATCH_GET_CHILD ); // we can limit the recursion-depth, but will it be helpful or From 2c9b2c1d67be54f0c7ceb23986e6099b40e7011f Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sat, 20 Aug 2022 10:44:05 +0200 Subject: [PATCH 07/11] fixes for finishing installation correctly Signed-off-by: Michael Kaufmann --- actions/admin/settings/185.spf.php | 2 +- install/install.php | 5 ++--- lib/Froxlor/Cli/InstallCommand.php | 11 ++++++++++- lib/Froxlor/Install/Install.php | 16 ++++++++++++++-- lib/Froxlor/Install/Install/Core.php | 20 ++++++++++++++++++++ lib/formfields/install/formfield.install.php | 6 ++++-- templates/Froxlor/form/formfields.html.twig | 2 +- 7 files changed, 52 insertions(+), 10 deletions(-) diff --git a/actions/admin/settings/185.spf.php b/actions/admin/settings/185.spf.php index 51d7b9a2..0a5fd16b 100644 --- a/actions/admin/settings/185.spf.php +++ b/actions/admin/settings/185.spf.php @@ -29,7 +29,7 @@ return [ 'title' => lng('admin.spfsettings'), 'icon' => 'fa-solid fa-clipboard-check', 'fields' => [ - 'spf_enabled' => [ + 'use_spf' => [ 'label' => lng('spf.use_spf'), 'settinggroup' => 'spf', 'varname' => 'use_spf', diff --git a/install/install.php b/install/install.php index b0bded86..b585c1b6 100644 --- a/install/install.php +++ b/install/install.php @@ -51,10 +51,9 @@ if (!file_exists(dirname(__DIR__) . '/vendor/autoload.php')) { } // check installation status -// @fixme userdata.inc.php is created iun step3 so step4 is never shown if (file_exists(dirname(__DIR__) . '/lib/userdata.inc.php')) { - http_response_code(404); - die(); + header("Location: ../"); + exit; } require dirname(__DIR__) . '/vendor/autoload.php'; diff --git a/lib/Froxlor/Cli/InstallCommand.php b/lib/Froxlor/Cli/InstallCommand.php index 94858e0c..bfcc7721 100644 --- a/lib/Froxlor/Cli/InstallCommand.php +++ b/lib/Froxlor/Cli/InstallCommand.php @@ -49,13 +49,22 @@ final class InstallCommand extends Command $this->setName('froxlor:install'); $this->setDescription('Installation process to use instead of web-ui'); $this->addArgument('input-file', InputArgument::OPTIONAL, 'Optional JSON array file to use for unattended installations'); - $this->addOption('print-example-file', 'p', InputOption::VALUE_NONE, 'Outputs an example JSON content to be used with the input file parameter'); + $this->addOption('print-example-file', 'p', InputOption::VALUE_NONE, 'Outputs an example JSON content to be used with the input file parameter') + ->addOption('create-userdata-from-str', 'c', InputOption::VALUE_REQUIRED, 'Creates lib/userdata.inc.php file from string created by web-install process'); } protected function execute(InputInterface $input, OutputInterface $output) { $result = self::SUCCESS; + if ($input->getOption('create-userdata-from-str') !== false) { + $ud_str = $input->getOption('create-userdata-from-str'); + $ud_dec = json_decode(base64_decode($ud_str), true); + $core = new Core($ud_dec); + $core->createUserdataConf(); + return $result; + } + session_start(); require __DIR__ . '/install.functions.php'; diff --git a/lib/Froxlor/Install/Install.php b/lib/Froxlor/Install/Install.php index 07df0261..ff423d00 100644 --- a/lib/Froxlor/Install/Install.php +++ b/lib/Froxlor/Install/Install.php @@ -404,8 +404,20 @@ class Install $default = 'bullseye'; // read os-release - if (@file_exists('/etc/os-release')) { - $os_dist = parse_ini_file('/etc/os-release', false); + if (@file_exists('/etc/os-release') && is_readable('/etc/os-release')) { + if (function_exists('parse_ini_file')) { + $os_dist = parse_ini_file('/etc/os-release', false); + } else { + $osrf = explode("\n", file_get_contents('/etc/os-release')); + foreach ($osrf as $line) { + $osrfline = explode("\n", $line); + if ($osrfline[0] == 'VERSION_CODENAME') { + $os_dist['VERSION_CODENAME'] = $osrfline[1]; + } else if ($osrfline[0] == 'ID') { + $os_dist['ID'] = $osrfline[1]; + } + } + } return strtolower($os_dist['VERSION_CODENAME'] ?? ($os_dist['ID'] ?? $default)); } return $default; diff --git a/lib/Froxlor/Install/Install/Core.php b/lib/Froxlor/Install/Install/Core.php index 9d65f55e..9ae7099a 100644 --- a/lib/Froxlor/Install/Install/Core.php +++ b/lib/Froxlor/Install/Install/Core.php @@ -116,6 +116,7 @@ class Core $this->doDataEntries($pdo); // create JSON array for config-services $this->createJsonArray(); + $this->createUserdataParamStr(); } public function getUnprivilegedPdo(): PDO @@ -675,4 +676,23 @@ class Core ]; $_SESSION['installation']['json_params'] = json_encode($json_params); } + + private function createUserdataParamStr() + { + $req_fields = [ + 'mysql_host', + 'mysql_unprivileged_user', + 'mysql_unprivileged_pass', + 'mysql_database', + 'mysql_root_user', + 'mysql_root_pass', + 'mysql_ssl_ca_file', + 'mysql_ssl_verify_server_certificate' + ]; + $json_params = []; + foreach ($req_fields as $field) { + $json_params[$field] = $this->validatedData[$field] ?? ""; + } + $_SESSION['installation']['ud_str'] = base64_encode(json_encode($json_params)); + } } diff --git a/lib/formfields/install/formfield.install.php b/lib/formfields/install/formfield.install.php index dda57fbb..1d5d7f04 100644 --- a/lib/formfields/install/formfield.install.php +++ b/lib/formfields/install/formfield.install.php @@ -220,9 +220,11 @@ return [ 'system' => [ 'label' => lng('install.install.runcmd'), 'type' => 'textarea', - 'value' => !empty($_SESSION['installation']['json_params']) ? Froxlor::getInstallDir() . "bin/froxlor-cli froxlor:config-services -a '" . $_SESSION['installation']['json_params'] . "' --yes-to-all" : "something went wrong...", + 'value' => (!empty($_SESSION['installation']['ud_str']) ? Froxlor::getInstallDir() . "bin/froxlor-cli froxlor:install -c '" . $_SESSION['installation']['ud_str'] . "'" : "something went wrong...") . "\n" . + (!empty($_SESSION['installation']['json_params']) ? Froxlor::getInstallDir() . "bin/froxlor-cli froxlor:config-services -a '" . $_SESSION['installation']['json_params'] . "' --yes-to-all" : "something went wrong..."), 'readonly' => true, - 'rows' => 3 + 'rows' => 10, + 'style' => 'min-height:16rem;' ], 'manual_config' => [ 'label' => lng('install.install.manual_config'), diff --git a/templates/Froxlor/form/formfields.html.twig b/templates/Froxlor/form/formfields.html.twig index 6c632df6..4151475e 100644 --- a/templates/Froxlor/form/formfields.html.twig +++ b/templates/Froxlor/form/formfields.html.twig @@ -201,7 +201,7 @@ {% endmacro %} {% macro textarea(id, field) %} - + {% endmacro %} {% macro link(id, field) %} From 07094f231ac0631c9c7ec2e21932567b190a66e2 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sat, 20 Aug 2022 11:21:49 +0200 Subject: [PATCH 08/11] minor fixes in installation process Signed-off-by: Michael Kaufmann --- lib/Froxlor/Cli/InstallCommand.php | 17 +++++++++++------ lib/Froxlor/Install/Install/Core.php | 6 ++++-- lib/formfields/install/formfield.install.php | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/Froxlor/Cli/InstallCommand.php b/lib/Froxlor/Cli/InstallCommand.php index bfcc7721..03e1a107 100644 --- a/lib/Froxlor/Cli/InstallCommand.php +++ b/lib/Froxlor/Cli/InstallCommand.php @@ -57,12 +57,16 @@ final class InstallCommand extends Command { $result = self::SUCCESS; - if ($input->getOption('create-userdata-from-str') !== false) { + if ($input->getOption('create-userdata-from-str') !== null) { $ud_str = $input->getOption('create-userdata-from-str'); - $ud_dec = json_decode(base64_decode($ud_str), true); - $core = new Core($ud_dec); - $core->createUserdataConf(); - return $result; + $ud_dec = @json_decode(@base64_decode($ud_str), true); + if (is_array($ud_dec) && !empty($ud_dec) && count($ud_dec) == 8) { + $core = new Core($ud_dec); + $core->createUserdataConf(); + return $result; + } + $output->writeln("Invalid parameter value."); + return self::INVALID; } session_start(); @@ -130,6 +134,7 @@ final class InstallCommand extends Command $this->io->info('Running unattended installation'); } else { $extended = $this->io->confirm('Use advanced installation mode?', false); + $decoded_input = []; } $result = $this->showStep(0, $extended, $decoded_input); @@ -246,7 +251,7 @@ final class InstallCommand extends Command if ($step == 3) { // do actual install with data from $this->formfielddata $core = new Core($this->formfielddata); - $core->doInstall(); + $core->doInstall(false); $core->createUserdataConf(); } return $this->showStep(++$step, $extended, $decoded_input); diff --git a/lib/Froxlor/Install/Install/Core.php b/lib/Froxlor/Install/Install/Core.php index 9ae7099a..e9ed07b3 100644 --- a/lib/Froxlor/Install/Install/Core.php +++ b/lib/Froxlor/Install/Install/Core.php @@ -52,7 +52,7 @@ class Core * @return void * @throws Exception */ - public function doInstall() + public function doInstall(bool $create_ud_str = true) { $options = [ 'PDO::MYSQL_ATTR_INIT_COMMAND' => 'SET names utf8' @@ -116,7 +116,9 @@ class Core $this->doDataEntries($pdo); // create JSON array for config-services $this->createJsonArray(); - $this->createUserdataParamStr(); + if ($create_ud_str) { + $this->createUserdataParamStr(); + } } public function getUnprivilegedPdo(): PDO diff --git a/lib/formfields/install/formfield.install.php b/lib/formfields/install/formfield.install.php index 1d5d7f04..4b34b939 100644 --- a/lib/formfields/install/formfield.install.php +++ b/lib/formfields/install/formfield.install.php @@ -220,7 +220,7 @@ return [ 'system' => [ 'label' => lng('install.install.runcmd'), 'type' => 'textarea', - 'value' => (!empty($_SESSION['installation']['ud_str']) ? Froxlor::getInstallDir() . "bin/froxlor-cli froxlor:install -c '" . $_SESSION['installation']['ud_str'] . "'" : "something went wrong...") . "\n" . + 'value' => (!empty($_SESSION['installation']['ud_str']) ? Froxlor::getInstallDir() . "bin/froxlor-cli froxlor:install -c '" . $_SESSION['installation']['ud_str'] . "'\n" : "") . (!empty($_SESSION['installation']['json_params']) ? Froxlor::getInstallDir() . "bin/froxlor-cli froxlor:config-services -a '" . $_SESSION['installation']['json_params'] . "' --yes-to-all" : "something went wrong..."), 'readonly' => true, 'rows' => 10, From 3ee04a6e75fb43da90c71af897cce6cb0341266f Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sat, 20 Aug 2022 13:44:44 +0200 Subject: [PATCH 09/11] install-finish-magic Signed-off-by: Michael Kaufmann --- actions/admin/settings/122.froxlorvhost.php | 2 +- install/froxlor.sql.php | 2 +- lib/Froxlor/UI/Panel/UI.php | 13 +++-- lib/formfields/install/formfield.install.php | 6 ++- lng/de.lng.php | 1 + lng/en.lng.php | 1 + templates/Froxlor/install/index.html.twig | 3 +- .../Froxlor/misc/ownershiphint.html.twig | 2 +- .../Froxlor/src/js/components/install.js | 47 ++++++++++++++++++- 9 files changed, 66 insertions(+), 11 deletions(-) diff --git a/actions/admin/settings/122.froxlorvhost.php b/actions/admin/settings/122.froxlorvhost.php index eb17552f..4f8c3871 100644 --- a/actions/admin/settings/122.froxlorvhost.php +++ b/actions/admin/settings/122.froxlorvhost.php @@ -42,7 +42,7 @@ return [ 'settinggroup' => 'system', 'varname' => 'froxlordirectlyviahostname', 'type' => 'checkbox', - 'default' => false, + 'default' => true, 'save_method' => 'storeSettingField' ], 'system_froxloraliases' => [ diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index 01f1d38d..a334844a 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -598,7 +598,7 @@ opcache.validate_timestamps'), ('system', 'ftpserver', 'proftpd'), ('system', 'dns_createmailentry', '0'), ('system', 'dns_createcaaentry', '1'), - ('system', 'froxlordirectlyviahostname', '0'), + ('system', 'froxlordirectlyviahostname', '1'), ('system', 'report_enable', '1'), ('system', 'report_webmax', '90'), ('system', 'report_trafficmax', '90'), diff --git a/lib/Froxlor/UI/Panel/UI.php b/lib/Froxlor/UI/Panel/UI.php index 0fc201ef..dd68d7ad 100644 --- a/lib/Froxlor/UI/Panel/UI.php +++ b/lib/Froxlor/UI/Panel/UI.php @@ -163,11 +163,14 @@ class UI self::$install_mode = $install_mode; // init twig template engine $loader = new FilesystemLoader(Froxlor::getInstallDir() . '/templates/'); - self::$twig = new Environment($loader, [ - 'debug' => true, - 'cache' => Froxlor::getInstallDir() . '/cache', - 'auto_reload' => true - ]); + $twig_params = [ + 'auto_reload' => true, + 'debug' => false, + ]; + if (is_writable(Froxlor::getInstallDir() . '/cache')) { + $twig_params['cache'] = Froxlor::getInstallDir() . '/cache'; + } + self::$twig = new Environment($loader, $twig_params); self::$twig->addExtension(new DebugExtension()); self::$twig->addExtension(new CustomReflection()); self::$twig->addExtension(new FroxlorTwig()); diff --git a/lib/formfields/install/formfield.install.php b/lib/formfields/install/formfield.install.php index 4b34b939..9a424d06 100644 --- a/lib/formfields/install/formfield.install.php +++ b/lib/formfields/install/formfield.install.php @@ -231,7 +231,11 @@ return [ 'type' => 'checkbox', 'value' => '1', 'checked' => old('manual_config', '0', 'installation'), - ] + ], + 'target_servername' => [ + 'type' => 'hidden', + 'value' => $_SESSION['installation']['servername'] ?? "", + ], ] ] ] diff --git a/lng/de.lng.php b/lng/de.lng.php index 71c244a0..bb913aa7 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -2169,6 +2169,7 @@ Vielen Dank, Ihr Administrator', 'description' => 'Der untenstehende Befehl lädt, installiert und konfiguriert die benötigten Dienste auf dem System aufgrund der Angaben die während des Installationsprozessen gesammelt wurden.', 'runcmd' => 'Folgenden Befehl als root-Benutzer in der Shell auf dem Server ausführen:', 'manual_config' => 'Ich werden die Dienste manuell konfigurieren, direkt zum Login umleiten', + 'waitforconfig' => 'Warte auf Abschluss der Dienstkonfiguration...', ], 'errors' => [ 'wrong_ownership' => 'Die froxlor Dateien gehören nicht vollständig dem Benutzer %s:%s', diff --git a/lng/en.lng.php b/lng/en.lng.php index ac6fcc82..8aad9f02 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -2555,6 +2555,7 @@ Yours sincerely, your administrator', 'description' => 'The command below will download, install and configure required services on your system according to the data you have given in this installation process.', 'runcmd' => 'Run the following command as root-user in your shell on this server:', 'manual_config' => 'I will manually configure the services, just take me to the login', + 'waitforconfig' => 'Waiting for services to be configured...', ], 'errors' => [ 'wrong_ownership' => 'Make sure the froxlor files are owned by %s:%s', diff --git a/templates/Froxlor/install/index.html.twig b/templates/Froxlor/install/index.html.twig index 96ded525..2aa7c078 100644 --- a/templates/Froxlor/install/index.html.twig +++ b/templates/Froxlor/install/index.html.twig @@ -60,7 +60,8 @@ « {{ lng('panel.back') }} {% else %} - + {{ lng('install.install.waitforconfig') }} + {% endif %} {% else %} diff --git a/templates/Froxlor/misc/ownershiphint.html.twig b/templates/Froxlor/misc/ownershiphint.html.twig index be6b3401..a1f63ee9 100644 --- a/templates/Froxlor/misc/ownershiphint.html.twig +++ b/templates/Froxlor/misc/ownershiphint.html.twig @@ -11,7 +11,7 @@
chown -R {{ user }}:{{ group }} {{ installdir }}

- Start install + Reload

diff --git a/templates/Froxlor/src/js/components/install.js b/templates/Froxlor/src/js/components/install.js index 9c29a4a1..4f076252 100644 --- a/templates/Froxlor/src/js/components/install.js +++ b/templates/Froxlor/src/js/components/install.js @@ -4,7 +4,7 @@ $(function () { */ $('#switchInstallMode').on('click', function () { var checked = $(this).prop('checked'); - window.location = '/install/install.php' + replaceQueryParam('extended', +checked, window.location.search); + window.location = window.location.pathname + replaceQueryParam('extended', +checked, window.location.search); }); function replaceQueryParam(param, newval, search) { @@ -14,4 +14,49 @@ $(function () { } return search + '&' + param + '=' + newval; } + + function checkConfigState() { + $.ajax({ + url: window.location.href, + type: "GET", + success: function (data, textStatus, request) { + if (request.status >= 300) { + window.location = "http://" + srvName; + } + }, + error: function (request, textStatus, errorThrown) { + // continue + if (request.status >= 300) { + window.location = "http://" + srvName; + } + } + }); + } + + var cTimer; + + /** + * check manual-config switch + */ + $('#manual_config').on('click', function () { + clearInterval(cTimer); + var checked = $(this).prop('checked'); + if (checked) { + // button zum login + $('#submitAuto').addClass('d-none'); + $('#submitManual').removeClass('d-none'); + } else { + cTimer = setInterval(checkConfigState, 1000); + // spinner fürs warten + $('#submitAuto').removeClass('d-none'); + $('#submitManual').addClass('d-none'); + } + }); + + if ($('#manual_config').length > 0) { + var srvName = $('#target_servername').val(); + clearInterval(cTimer); + cTimer = setInterval(checkConfigState, 1000); + } + }); From f389226aae64f4bea33031ffa45c29bda2e20cf1 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 21 Aug 2022 11:43:25 +0200 Subject: [PATCH 10/11] fix styling of deactivated/locked customers in overview and 0-value in edit-form Signed-off-by: Michael Kaufmann --- lib/Froxlor/Api/Commands/PhpSettings.php | 2 +- lib/Froxlor/UI/Callbacks/Style.php | 15 +++++++++++++ .../customer/formfield.customer_edit.php | 21 ++++++++++--------- .../admin/tablelisting.customers.php | 6 +++++- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/Froxlor/Api/Commands/PhpSettings.php b/lib/Froxlor/Api/Commands/PhpSettings.php index 86d9b562..d417b70e 100644 --- a/lib/Froxlor/Api/Commands/PhpSettings.php +++ b/lib/Froxlor/Api/Commands/PhpSettings.php @@ -123,7 +123,7 @@ class PhpSettings extends ApiCommand implements ResourceEntity } // check whether we use that config as froxor-vhost config - if (Settings::Get('system.mod_fcgid_defaultini_ownvhost') == $row['id'] || Settings::Get('phpfpm.vhost_defaultini') == $row['id']) { + if ((Settings::Get('system.mod_fcgid') == '1' && Settings::Get('system.mod_fcgid_defaultini_ownvhost') == $row['id']) || (Settings::Get('phpfpm.enabled') == '1' && Settings::Get('phpfpm.vhost_defaultini') == $row['id'])) { $domains[] = Settings::Get('system.hostname'); } diff --git a/lib/Froxlor/UI/Callbacks/Style.php b/lib/Froxlor/UI/Callbacks/Style.php index a7211e1d..7de6941b 100644 --- a/lib/Froxlor/UI/Callbacks/Style.php +++ b/lib/Froxlor/UI/Callbacks/Style.php @@ -66,6 +66,21 @@ class Style return $attributes['fields']['deactivated'] ? 'bg-info' : $termination_css; } + public static function resultCustomerLockedOrDeactivated(array $attributes): string + { + $row_css = ''; + if ((int)$attributes['fields']['deactivated'] == 1) { + $row_css = 'bg-info'; + } elseif ( + $attributes['fields']['loginfail_count'] >= Settings::Get('login.maxloginattempts') + && $attributes['fields']['lastlogin_fail'] > (time() - Settings::Get('login.deactivatetime')) + ) { + $row_css = 'bg-warning'; + } + + return $row_css; + } + public static function diskspaceWarning(array $attributes): string { return self::getWarningStyle('diskspace', $attributes['fields'], (int)Settings::Get('system.report_webmax')); diff --git a/lib/formfields/admin/customer/formfield.customer_edit.php b/lib/formfields/admin/customer/formfield.customer_edit.php index 9097aef6..172099c3 100644 --- a/lib/formfields/admin/customer/formfield.customer_edit.php +++ b/lib/formfields/admin/customer/formfield.customer_edit.php @@ -195,49 +195,49 @@ return [ 'diskspace' => [ 'label' => lng('customer.diskspace') . ' (' . lng('customer.mib') . ')', 'type' => 'textul', - 'value' => $result['diskspace'], + 'value' => empty($result['diskspace']) ? '0' : $result['diskspace'], 'maxlength' => 16, 'mandatory' => true ], 'traffic' => [ 'label' => lng('customer.traffic') . ' (' . lng('customer.gib') . ')', 'type' => 'textul', - 'value' => $result['traffic'], + 'value' => empty($result['traffic']) ? '0' : $result['traffic'], 'maxlength' => 14, 'mandatory' => true ], 'subdomains' => [ 'label' => lng('customer.subdomains'), 'type' => 'textul', - 'value' => $result['subdomains'], + 'value' => empty($result['subdomains']) ? '0' : $result['subdomains'], 'maxlength' => 9, 'mandatory' => true ], 'emails' => [ 'label' => lng('customer.emails'), 'type' => 'textul', - 'value' => $result['emails'], + 'value' => empty($result['emails']) ? '0' : $result['emails'], 'maxlength' => 9, 'mandatory' => true ], 'email_accounts' => [ 'label' => lng('customer.accounts'), 'type' => 'textul', - 'value' => $result['email_accounts'], + 'value' => empty($result['email_accounts']) ? '0' : $result['email_accounts'], 'maxlength' => 9, 'mandatory' => true ], 'email_forwarders' => [ 'label' => lng('customer.forwarders'), 'type' => 'textul', - 'value' => $result['email_forwarders'], + 'value' => empty($result['email_forwarders']) ? '0' : $result['email_forwarders'], 'maxlength' => 9, 'mandatory' => true ], 'email_quota' => [ 'label' => lng('customer.email_quota') . ' (' . lng('customer.mib') . ')', 'type' => 'textul', - 'value' => $result['email_quota'], + 'value' => empty($result['email_quota']) ? '0' : $result['email_quota'], 'maxlength' => 9, 'visible' => Settings::Get('system.mail_quota_enabled') == '1', 'mandatory' => true @@ -259,13 +259,14 @@ return [ 'ftps' => [ 'label' => lng('customer.ftps'), 'type' => 'textul', - 'value' => $result['ftps'], - 'maxlength' => 9 + 'value' => empty($result['ftps']) ? '0' : $result['ftps'], + 'maxlength' => 9, + 'mandatory' => true ], 'mysqls' => [ 'label' => lng('customer.mysqls'), 'type' => 'textul', - 'value' => $result['mysqls'], + 'value' => empty($result['mysql']) ? '0' : $result['mysqls'], 'maxlength' => 9, 'mandatory' => true ], diff --git a/lib/tablelisting/admin/tablelisting.customers.php b/lib/tablelisting/admin/tablelisting.customers.php index 0e0fe011..c314a67b 100644 --- a/lib/tablelisting/admin/tablelisting.customers.php +++ b/lib/tablelisting/admin/tablelisting.customers.php @@ -27,6 +27,7 @@ use Froxlor\UI\Callbacks\Customer; use Froxlor\UI\Callbacks\Impersonate; use Froxlor\UI\Callbacks\ProgressBar; use Froxlor\UI\Callbacks\Text; +use Froxlor\UI\Callbacks\Style; use Froxlor\UI\Listing; return [ @@ -155,7 +156,7 @@ return [ 'unlock' => [ 'icon' => 'fa fa-unlock', 'title' => lng('panel.unlock'), - 'class' => 'text-warning', + 'class' => 'btn-outline-secondary', 'href' => [ 'section' => 'customers', 'page' => 'customers', @@ -186,5 +187,8 @@ return [ ], ], ], + 'format_callback' => [ + [Style::class, 'resultCustomerLockedOrDeactivated'] + ] ] ]; From bcda1d51c4d874f111fe5fa4e3d886f26d5b7e97 Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sun, 21 Aug 2022 12:47:20 +0200 Subject: [PATCH 11/11] added new cli command froxlor:user for unlocking, password-changing and info-display of a user Signed-off-by: Michael Kaufmann --- bin/froxlor-cli | 2 + lib/Froxlor/Cli/CliCommand.php | 55 ++++++++++++ lib/Froxlor/Cli/RunApiCommand.php | 53 ------------ lib/Froxlor/Cli/UserCommand.php | 135 ++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 53 deletions(-) create mode 100644 lib/Froxlor/Cli/UserCommand.php diff --git a/bin/froxlor-cli b/bin/froxlor-cli index 26bdc2b7..b7e6d566 100755 --- a/bin/froxlor-cli +++ b/bin/froxlor-cli @@ -34,6 +34,7 @@ use Froxlor\Cli\SwitchServerIp; use Froxlor\Cli\UpdateCommand; use Froxlor\Cli\InstallCommand; use Froxlor\Cli\MasterCron; +use Froxlor\Cli\UserCommand; use Froxlor\Froxlor; // validate correct php version @@ -57,4 +58,5 @@ $application->add(new SwitchServerIp()); $application->add(new UpdateCommand()); $application->add(new InstallCommand()); $application->add(new MasterCron()); +$application->add(new UserCommand()); $application->run(); diff --git a/lib/Froxlor/Cli/CliCommand.php b/lib/Froxlor/Cli/CliCommand.php index 5c154a27..8cc93a1c 100644 --- a/lib/Froxlor/Cli/CliCommand.php +++ b/lib/Froxlor/Cli/CliCommand.php @@ -25,6 +25,7 @@ namespace Froxlor\Cli; +use PDO; use Exception; use Froxlor\Froxlor; use Froxlor\Settings; @@ -61,6 +62,60 @@ class CliCommand extends Command return self::SUCCESS; } + protected function getUserByName(?string $loginname, bool $deactivated_check = true): array + { + if (empty($loginname)) { + throw new Exception("Empty username"); + } + + $stmt = Database::prepare(" + SELECT `loginname` AS `customer` + FROM `" . TABLE_PANEL_CUSTOMERS . "` + WHERE `loginname`= :loginname + "); + Database::pexecute($stmt, [ + "loginname" => $loginname + ]); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($row && $row['customer'] == $loginname) { + $table = "`" . TABLE_PANEL_CUSTOMERS . "`"; + $adminsession = '0'; + } else { + $stmt = Database::prepare(" + SELECT `loginname` AS `admin` FROM `" . TABLE_PANEL_ADMINS . "` + WHERE `loginname`= :loginname + "); + Database::pexecute($stmt, [ + "loginname" => $loginname + ]); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($row && $row['admin'] == $loginname) { + $table = "`" . TABLE_PANEL_ADMINS . "`"; + $adminsession = '1'; + } else { + throw new Exception("Unknown user '" . $loginname . "'"); + } + } + + $userinfo_stmt = Database::prepare(" + SELECT * FROM $table + WHERE `loginname`= :loginname + "); + Database::pexecute($userinfo_stmt, [ + "loginname" => $loginname + ]); + $userinfo = $userinfo_stmt->fetch(PDO::FETCH_ASSOC); + $userinfo['adminsession'] = $adminsession; + + if ($deactivated_check && $userinfo['deactivated']) { + throw new Exception("User '" . $loginname . "' is currently deactivated"); + } + + return $userinfo; + } + private function runUpdate(OutputInterface $output): int { $output->writeln('Automatic update is activated and we are going to proceed without any notices'); diff --git a/lib/Froxlor/Cli/RunApiCommand.php b/lib/Froxlor/Cli/RunApiCommand.php index 8ed316fc..5a070f42 100644 --- a/lib/Froxlor/Cli/RunApiCommand.php +++ b/lib/Froxlor/Cli/RunApiCommand.php @@ -126,57 +126,4 @@ final class RunApiCommand extends CliCommand return ['class' => $command[0], 'function' => $command[1]]; } - private function getUserByName(?string $loginname): array - { - if (empty($loginname)) { - throw new Exception("Empty username"); - } - - $stmt = Database::prepare(" - SELECT `loginname` AS `customer` - FROM `" . TABLE_PANEL_CUSTOMERS . "` - WHERE `loginname`= :loginname - "); - Database::pexecute($stmt, [ - "loginname" => $loginname - ]); - $row = $stmt->fetch(PDO::FETCH_ASSOC); - - if ($row && $row['customer'] == $loginname) { - $table = "`" . TABLE_PANEL_CUSTOMERS . "`"; - $adminsession = '0'; - } else { - $stmt = Database::prepare(" - SELECT `loginname` AS `admin` FROM `" . TABLE_PANEL_ADMINS . "` - WHERE `loginname`= :loginname - "); - Database::pexecute($stmt, [ - "loginname" => $loginname - ]); - $row = $stmt->fetch(PDO::FETCH_ASSOC); - - if ($row && $row['admin'] == $loginname) { - $table = "`" . TABLE_PANEL_ADMINS . "`"; - $adminsession = '1'; - } else { - throw new Exception("Unknown user '" . $loginname . "'"); - } - } - - $userinfo_stmt = Database::prepare(" - SELECT * FROM $table - WHERE `loginname`= :loginname - "); - Database::pexecute($userinfo_stmt, [ - "loginname" => $loginname - ]); - $userinfo = $userinfo_stmt->fetch(PDO::FETCH_ASSOC); - $userinfo['adminsession'] = $adminsession; - - if ($userinfo['deactivated']) { - throw new Exception("User '" . $loginname . "' is currently deactivated"); - } - - return $userinfo; - } } diff --git a/lib/Froxlor/Cli/UserCommand.php b/lib/Froxlor/Cli/UserCommand.php new file mode 100644 index 00000000..33caef39 --- /dev/null +++ b/lib/Froxlor/Cli/UserCommand.php @@ -0,0 +1,135 @@ + + * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 + */ + +namespace Froxlor\Cli; + +use Exception; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Froxlor\Api\Commands\Admins; +use Froxlor\Api\Commands\Customers; +use Froxlor\System\Crypt; +use Froxlor\Froxlor; + +final class UserCommand extends CliCommand +{ + + protected function configure() + { + $this->setName('froxlor:user'); + $this->setDescription('Various user actions'); + $this->addArgument('user', InputArgument::REQUIRED, 'Loginname of the target user') + ->addArgument('admin', InputArgument::OPTIONAL, 'Loginname of the executing admin/reseller user', 'admin'); + $this->addOption('unlock', 'u', InputOption::VALUE_NONE, 'Unock user after too many failed login attempts') + ->addOption('change-passwd', 'p', InputOption::VALUE_NONE, 'Set new password for given user') + ->addOption('show-info', 's', InputOption::VALUE_NONE, 'Output information details of given user'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $result = self::SUCCESS; + + $result = $this->validateRequirements($input, $output); + + require Froxlor::getInstallDir() . '/lib/functions.php'; + + // set error-handler + @set_error_handler([ + '\\Froxlor\\Api\\Api', + 'phpErrHandler' + ]); + + if ($result == self::SUCCESS) { + try { + $adminname = $input->getArgument('admin'); + $admininfo = $this->getUserByName($adminname); + $loginname = $input->getArgument('user'); + $userinfo = $this->getUserByName($loginname, false); + + $do_unlock = $input->getOption('unlock'); + $do_passwd = $input->getOption('change-passwd'); + $do_show = $input->getOption('show-info'); + + if ($do_unlock === false && $do_passwd === false && $do_show === false) { + $output->writeln('No option given, nothing to do.'); + $result = self::INVALID; + } + + if ($do_unlock !== false) { + // unlock given user + if ((int)$userinfo['adminsession'] == 1) { + Admins::getLocal($admininfo, ['loginname' => $loginname])->unlock(); + } else { + Customers::getLocal($admininfo, ['loginname' => $loginname])->unlock(); + } + $output->writeln('User ' . $loginname . ' unlocked successfully'); + $result = self::SUCCESS; + } + if ($result == self::SUCCESS && $do_passwd !== false) { + $io = new SymfonyStyle($input, $output); + $passwd = $io->askHidden("Enter new password", function ($value) { + if (empty($value)) { + throw new \RuntimeException('You must enter a value.'); + } + $value = Crypt::validatePassword($value, 'new password'); + return $value; + }); + $passwd2 = $io->askHidden("Confirm new password", function ($value) use ($passwd) { + if (empty($value)) { + throw new \RuntimeException('You must enter a value.'); + } elseif ($value != $passwd) { + throw new \RuntimeException('Passwords do not match'); + } + return $value; + }); + if ((int)$userinfo['adminsession'] == 1) { + Admins::getLocal($admininfo, ['id' => $userinfo['adminid'], 'admin_password' => $passwd])->update(); + } else { + Customers::getLocal($admininfo, ['id' => $userinfo['customerid'], 'new_customer_password' => $passwd])->update(); + } + $output->writeln('Changed password for ' . $loginname . ''); + $result = self::SUCCESS; + } + if ($result == self::SUCCESS && $do_show !== false) { + $userinfo['password'] = '[hidden]'; + $userinfo['data_2fa'] = '[hidden]'; + $io = new SymfonyStyle($input, $output); + $io->horizontalTable( + array_keys($userinfo), + [array_values($userinfo)] + ); + } + } catch (Exception $e) { + $output->writeln('' . $e->getMessage() . ''); + $result = self::FAILURE; + } + } + + return $result; + } +}