Merge tag '0.10.35.1' into private-0.10.33-dmarc

tagging release 0.10.35.1
This commit is contained in:
2022-06-20 20:06:59 +02:00
148 changed files with 167 additions and 105 deletions

View File

@@ -297,6 +297,10 @@ abstract class ApiCommand extends ApiParameter
$sortfield[$id] = $sfield;
}
$field = implode('.', $sortfield);
if (preg_match('/^([a-z0-9\-\._`]+)$/i', $field) == false) {
// skip
continue;
}
if (! $first) {
$condition .= ' AND ';
}
@@ -313,6 +317,14 @@ abstract class ApiCommand extends ApiParameter
} elseif (strtolower($valoper['op']) == 'in' && is_array($valoper['value']) && count($valoper['value']) > 0) {
$condition .= $field . ' ' . $valoper['op'] . ' (';
foreach ($valoper['value'] as $incnt => $invalue) {
if (!is_numeric($incnt)) {
// skip
continue;
}
if (!empty($invalue) && preg_match('/^([a-z0-9\-\._`]+)$/i', $invalue) == false) {
// skip
continue;
}
$condition .= ":" . $cleanfield . $incnt . ", ";
$query_fields[':' . $cleanfield . $incnt] = $invalue ?? '';
}
@@ -398,6 +410,10 @@ abstract class ApiCommand extends ApiParameter
$sortfield[$id] = $sfield;
}
$field = implode('.', $sortfield);
if (preg_match('/^([a-z0-9\-\._`]+)$/i', $field) == false) {
// skip
continue;
}
$by = strtoupper($by);
if (! in_array($by, [
'ASC',
@@ -423,6 +439,7 @@ abstract class ApiCommand extends ApiParameter
return $order;
}
/**
* return logger instance
*

View File

@@ -472,7 +472,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
// parameters
$name = $this->getParam('name', true, $result['name']);
$idna_convert = new \Froxlor\Idna\IdnaWrapper();
$email = $this->getParam('email', true, $idna_convert->decode($result['email']));
$email = $this->getParam('email', true, $idna_convert->decode($result['email'] ?? ''));
$password = $this->getParam('admin_password', true, '');
$def_language = $this->getParam('def_language', true, $result['def_language']);
$custom_notes = $this->getParam('custom_notes', true, $result['custom_notes']);

View File

@@ -954,7 +954,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$move_to_admin = (int) ($this->getParam('move_to_admin', true, 0));
$idna_convert = new \Froxlor\Idna\IdnaWrapper();
$email = $this->getParam('email', true, $idna_convert->decode($result['email']));
$email = $this->getParam('email', true, $idna_convert->decode($result['email'] ?? ''));
$name = $this->getParam('name', true, $result['name']);
$firstname = $this->getParam('firstname', true, $result['firstname']);
$company_required = empty($result['company']) && ((! empty($name) && empty($firstname)) || (empty($name) && ! empty($firstname)) || (empty($name) && empty($firstname)));

View File

@@ -197,6 +197,7 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
'NAME' => $customer['name'],
'FIRSTNAME' => $customer['firstname'],
'COMPANY' => $customer['company'],
'USERNAME' => $customer['loginname'],
'CUSTOMER_NO' => $customer['customernumber']
);

View File

@@ -243,6 +243,7 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
'NAME' => $customer['name'],
'FIRSTNAME' => $customer['firstname'],
'COMPANY' => $customer['company'],
'USERNAME' => $customer['loginname'],
'CUSTOMER_NO' => $customer['customernumber'],
'USR_NAME' => $username,
'USR_PASS' => htmlentities(htmlentities($password)),

View File

@@ -141,6 +141,7 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
'NAME' => $userinfo['name'],
'FIRSTNAME' => $userinfo['firstname'],
'COMPANY' => $userinfo['company'],
'USERNAME' => $userinfo['loginname'],
'CUSTOMER_NO' => $userinfo['customernumber'],
'DB_NAME' => $username,
'DB_PASS' => htmlentities(htmlentities($password)),

View File

View File

View File

View File

@@ -4,7 +4,6 @@ namespace Froxlor\Cli\Action;
use Froxlor\Database\Database;
use Froxlor\Settings;
use Froxlor\Cli\PhpSessioncleanCmd;
class PhpSessioncleanAction extends \Froxlor\Cli\Action
{

View File

View File

View File

@@ -182,7 +182,7 @@ class ConfigParser
}
/**
* Parse the XML and populate $this->services
* Parse the XML and populate $this->defaults
*
* @return bool
*/
@@ -194,9 +194,9 @@ class ConfigParser
}
// Get all defaults
$defaults = $this->xml->xpath('//defaults');
$defaults = $this->xml->xpath('//defaults/default');
foreach ($defaults as $default) {
$this->defaults = $default;
$this->defaults[] = $default;
}
// Switch flag to indicate we parsed our data

View File

View File

@@ -1,4 +1,5 @@
<?php
namespace Froxlor\Cron;
/**
@@ -18,6 +19,7 @@ namespace Froxlor\Cron;
* @since 0.10.0
*
*/
use Froxlor\Database\Database;
use Froxlor\Settings;
@@ -56,6 +58,12 @@ class CronConfig
SELECT * FROM `" . TABLE_PANEL_CRONRUNS . "` WHERE `isactive` = '1'
");
$binpath = Settings::Get("system.croncmdline");
// fallback as it is important
if ($binpath === null) {
$binpath = "/usr/bin/nice -n 5 /usr/bin/php -q";
}
$hour_delay = 0;
$day_delay = 5;
$month_delay = 7;
@@ -96,16 +104,16 @@ class CronConfig
}
// create entry-line
$binpath = Settings::Get("system.croncmdline");
// fallback as it is important
if ($binpath === null) {
$binpath = "/usr/bin/nice -n 5 /usr/bin/php -q";
}
$cronfile .= "root " . $binpath . " " . \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . "/scripts/froxlor_master_cronjob.php") . " --" . $row_cronentry['cronfile'] . " 1> /dev/null\n";
}
}
// php sessionclean if enabled
if ((int) Settings::Get('phpfpm.enabled') == 1) {
$cronfile .= "# Look for and purge old sessions every 30 minutes" . PHP_EOL;
$cronfile .= "09,39 * * * * root " . $binpath . " " . \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . "/scripts/php-sessionclean.php") . " --froxlor-dir=" . escapeshellarg(\Froxlor\Froxlor::getInstallDir()) . " 1> /dev/null" . PHP_EOL;
}
if (\Froxlor\FileDir::isFreeBSD()) {
// FreeBSD handles the cron-stuff in another way. We need to directly
// write to the crontab file as there is not cron.d/froxlor file
@@ -121,7 +129,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_master_cronjob\.php(.*)/", $ctl)) {
$newcrontab .= $ctl . "\n";
}
}

View File

View File

@@ -773,20 +773,28 @@ class Apache extends HttpConfigBase
}
if (Settings::Get('system.logfiles_piped') == '1' && Settings::Get('system.logfiles_script') != '') {
// replace for error_log
$command = \Froxlor\PhpHelper::replaceVariables(Settings::Get('system.logfiles_script'), array(
'LOGFILE' => $error_log,
'DOMAIN' => $domain['domain'],
'CUSTOMER' => $domain['loginname']
));
$logfiles_text .= ' ErrorLog "|' . $command . "\"\n";
// replace for access_log
$command = \Froxlor\PhpHelper::replaceVariables(Settings::Get('system.logfiles_script'), array(
'LOGFILE' => $access_log,
'DOMAIN' => $domain['domain'],
'CUSTOMER' => $domain['loginname']
));
$logfiles_text .= ' CustomLog "|' . $command . '" ' . $logtype . "\n";
if ($domain['writeerrorlog']) {
// replace for error_log
$command = \Froxlor\PhpHelper::replaceVariables(Settings::Get('system.logfiles_script'), array(
'LOGFILE' => $error_log,
'DOMAIN' => $domain['domain'],
'CUSTOMER' => $domain['loginname']
));
$logfiles_text .= ' ErrorLog "|' . $command . "\"\n";
} else {
$logfiles_text .= ' ErrorLog "' . $error_log . '"' . "\n";
}
if ($domain['writeaccesslog']) {
// replace for access_log
$command = \Froxlor\PhpHelper::replaceVariables(Settings::Get('system.logfiles_script'), array(
'LOGFILE' => $access_log,
'DOMAIN' => $domain['domain'],
'CUSTOMER' => $domain['loginname']
));
$logfiles_text .= ' CustomLog "|' . $command . '" ' . $logtype . "\n";
} else {
$logfiles_text .= ' CustomLog "' . $access_log . '" ' . $logtype . "\n";
}
} else {
$logfiles_text .= ' ErrorLog "' . $error_log . '"' . "\n";
$logfiles_text .= ' CustomLog "' . $access_log . '" ' . $logtype . "\n";

View File

@@ -635,6 +635,9 @@ EOC;
$acmesh_result = \Froxlor\FileDir::safe_exec(self::getAcmeSh() . " --upgrade --auto-upgrade 0");
// check for activated cron
$acmesh_result2 = \Froxlor\FileDir::safe_exec(self::getAcmeSh() . " --install-cronjob");
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Checking for LetsEncrypt client upgrades before renewing certificates:\n" . implode("\n", $acmesh_result) . "\n" . implode("\n", $acmesh_result2));
// set default CA
$acmesh_result3 = \Froxlor\FileDir::safe_exec(self::getAcmeSh() . " --set-default-ca --server " . self::$apiserver);
// log messages
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Checking for LetsEncrypt client upgrades before renewing certificates:\n" . implode("\n", $acmesh_result) . "\n" . implode("\n", $acmesh_result2) . "\n" . implode("\n", $acmesh_result3));
}
}

View File

@@ -251,7 +251,7 @@ class Lighttpd extends HttpConfigBase
// check for existence, #1485
if (! file_exists($domain['ssl_ca_file'])) {
$this->logger->logAction(\Froxlor\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";
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 = "' . \Froxlor\FileDir::makeCorrectFile($domain['ssl_ca_file']) . '"' . "\n";
}
@@ -760,6 +760,7 @@ class Lighttpd extends HttpConfigBase
'customerid' => $domain['customerid']
));
$diroption_text = '';
while ($row_htpasswds = $result_stmt->fetch(\PDO::FETCH_ASSOC)) {
if ($this->auth_backend_loaded[$domain['ipandport']] != 'yes' && $this->auth_backend_loaded[$domain['ssl_ipandport']] != 'yes') {
$filename = $domain['customerid'] . '.htpasswd';
@@ -836,6 +837,7 @@ class Lighttpd extends HttpConfigBase
}
}
$servernames_text = '';
for ($i = 0; $i < sizeof($server_string); $i ++) {
$data = $server_string[$i];

View File

View File

View File

@@ -324,8 +324,8 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron
if (file_exists($logsdir) && $logsdir != '/' && $logsdir != \Froxlor\FileDir::makeCorrectDir(Settings::Get('system.logfiles_directory')) && substr($logsdir, 0, strlen(Settings::Get('system.logfiles_directory'))) == Settings::Get('system.logfiles_directory')) {
// build up wildcard for webX-{access,error}.log{*}
$logfiles .= '-*';
\Froxlor\FileDir::safe_exec('rm -f ' . escapeshellarg($logfiles));
$logsdir .= '-*';
\Froxlor\FileDir::safe_exec('rm -f ' . escapeshellarg($logsdir));
}
}
}

View File

View File

@@ -36,7 +36,7 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
if ((int) Settings::Get('system.report_trafficmax') > 0) {
// Warn the customers at xx% traffic-usage
$result_stmt = Database::prepare("
SELECT `c`.`customerid`, `c`.`customernumber`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
SELECT `c`.`customerid`, `c`.`loginname`, `c`.`customernumber`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
`c`.`company`, `c`.`traffic`, `c`.`email`, `c`.`def_language`,
`a`.`name` AS `adminname`, `a`.`email` AS `adminmail`,
(SELECT SUM(`t`.`http` + `t`.`ftp_up` + `t`.`ftp_down` + `t`.`mail`)
@@ -67,6 +67,7 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
'NAME' => $rep_userinfo['name'],
'FIRSTNAME' => $rep_userinfo['firstname'],
'COMPANY' => $rep_userinfo['company'],
'USERNAME' => $rep_userinfo['loginname'],
'CUSTOMER_NO' => $rep_userinfo['customernumber'],
'TRAFFIC' => round(($row['traffic'] / 1024), 2), /* traffic is stored in KB, template uses MB */
'TRAFFICUSED' => round(($row['traffic_used'] / 1024), 2), /* traffic is stored in KB, template uses MB */
@@ -354,7 +355,7 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
* report about diskusage for customers
*/
$result_stmt = Database::query("
SELECT `c`.`customerid`, `c`.`customernumber`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
SELECT `c`.`customerid`, `c`.`loginname`, `c`.`customernumber`, `c`.`adminid`, `c`.`name`, `c`.`firstname`,
`c`.`company`, `c`.`diskspace`, `c`.`diskspace_used`, `c`.`email`, `c`.`def_language`,
`a`.`name` AS `adminname`, `a`.`email` AS `adminmail`
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c`
@@ -380,6 +381,7 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
'NAME' => $rep_userinfo['name'],
'FIRSTNAME' => $rep_userinfo['firstname'],
'COMPANY' => $rep_userinfo['company'],
'USERNAME' => $rep_userinfo['loginname'],
'CUSTOMER_NO' => $rep_userinfo['customernumber'],
'DISKAVAILABLE' => round(($row['diskspace'] / 1024), 2), /* traffic is stored in KB, template uses MB */
'DISKUSED' => round($row['diskspace_used'] / 1024, 2), /* traffic is stored in KB, template uses MB */

View File

View File

View File

View File

View File

View File

View File

View File

@@ -494,7 +494,7 @@ class FileDir
};
// create RecursiveIteratorIterator
$its = new \RecursiveIteratorIterator(new \RecursiveCallbackFilterIterator(new System\IgnorantRecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), $filter));
$its = new \RecursiveIteratorIterator(new \RecursiveCallbackFilterIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), $filter));
// we can limit the recursion-depth, but will it be helpful or
// will people start asking "why do I only see 2 subdirectories, i want to use /a/b/c"
// let's keep this in mind and see whether it will be useful

View File

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

View File

View File

View File

@@ -63,7 +63,7 @@ class PhpHelper
$subject[$field] = self::htmlentitiesArray($subject[$field], $fields, $quote_style, $charset);
}
}
} else {
} elseif (!empty($subject)) {
$subject = htmlentities($subject, $quote_style, $charset);
}

View File

View File

@@ -1,21 +0,0 @@
<?php
namespace Froxlor\System;
/**
* If you use RecursiveDirectoryIterator with RecursiveIteratorIterator and run
* into UnexpectedValueException you may use this little hack to ignore those
* directories, such as lost+found on linux.
* (User "antennen" @ http://php.net/manual/en/class.recursivedirectoryiterator.php#101654)
*/
class IgnorantRecursiveDirectoryIterator extends \RecursiveDirectoryIterator
{
public function getChildren()
{
try {
return new IgnorantRecursiveDirectoryIterator($this->getPathname());
} catch (\UnexpectedValueException $e) {
return new \RecursiveArrayIterator(array());
}
}
}

View File

View File

View File

View File

0
lib/Froxlor/index.html Normal file
View File

View File

@@ -1600,7 +1600,7 @@ root: root@<SERVERNAME>
# is /etc/mailname.
#myorigin = /etc/mailname
smtpd_banner = $myhostname ESMTP $mail_name (@@DISTRO@@)
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no
# appending .domain is the MUA's job.

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

0
lib/index.html Normal file
View File

View File