Merge remote-tracking branch 'origin/0.10.x' into private-0.10.35.1-dmarc

This commit is contained in:
2023-01-18 16:18:03 +01:00
28 changed files with 482 additions and 346 deletions

View File

@@ -27,12 +27,13 @@ use Froxlor\Database\Database;
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_API_KEYS . "` WHERE id = :id");
$success_message = "";
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
$id = isset($_POST['id']) ? (int) $_POST['id'] : (isset($_GET['id']) ? (int) $_GET['id'] : 0);
$area = AREA;
// do the delete and then just show a success-message and the apikeys list again
if ($action == 'delete') {
if ($id > 0) {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$chk = (AREA == 'admin' && $userinfo['customers_see_all'] == '1') ? true : false;
if (AREA == 'customer') {
$chk_stmt = Database::prepare("
@@ -61,8 +62,17 @@ if ($action == 'delete') {
));
$success_message = sprintf($lng['apikeys']['apikey_removed'], $id);
}
} else {
\Froxlor\UI\HTML::askYesNo('api_reallydelete', $filename, array(
'page' => $page,
'action' => $action,
'id' => $id
), $id);
}
}
} elseif ($action == 'add') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_API_KEYS . "` SET
`apikey` = :key, `secret` = :secret, `adminid` = :aid, `customerid` = :cid, `valid_until` = '-1', `allowed_from` = ''
@@ -82,8 +92,18 @@ if ($action == 'delete') {
'cid' => $cid
));
$success_message = $lng['apikeys']['apikey_added'];
} else {
\Froxlor\UI\HTML::askYesNo('api_reallyadd', $filename, array(
'page' => $page,
'action' => $action
), $id);
}
} elseif ($action == 'jqEditApiKey') {
$keyid = isset($_POST['id']) ? (int) $_POST['id'] : 0;
if (empty($keyid)) {
echo json_encode(false);
exit;
}
$allowed_from = isset($_POST['allowed_from']) ? $_POST['allowed_from'] : "";
$valid_until = isset($_POST['valid_until']) ? (int) $_POST['valid_until'] : -1;

View File

@@ -24,7 +24,7 @@ use Froxlor\Api\Commands\DomainZones as DomainZones;
// This file is being included in admin_domains and customer_domains
// and therefore does not need to require lib/init.php
$domain_id = isset($_GET['domain_id']) ? (int) $_GET['domain_id'] : null;
$domain_id = isset($_GET['domain_id']) ? (int) $_GET['domain_id'] : (isset($_POST['domain_id']) ? (int)$_POST['domain_id'] : null);
$record = isset($_POST['record']['record']) ? trim($_POST['record']['record']) : null;
$type = isset($_POST['record']['type']) ? $_POST['record']['type'] : 'A';
@@ -56,11 +56,11 @@ if ($action == 'add_record' && ! empty($_POST)) {
}
} elseif ($action == 'delete') {
// remove entry
$entry_id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
if ($entry_id > 0) {
if ($id > 0) {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
DomainZones::getLocal($userinfo, array(
'entry_id' => $entry_id,
'entry_id' => $id,
'id' => $domain_id
))->delete();
// success message (inline)
@@ -68,6 +68,14 @@ if ($action == 'add_record' && ! empty($_POST)) {
} catch (Exception $e) {
$errors = str_replace("\n", "<br>", $e->getMessage());
}
} else {
\Froxlor\UI\HTML::askYesNo('dnsentry_reallydelete', $filename, array(
'page' => $page,
'action' => $action,
'id' => $id,
'domain_id' => $domain_id
), $id);
}
}
}

View File

@@ -22,6 +22,7 @@ require './lib/init.php';
use Froxlor\Database\Database;
use Froxlor\Settings;
use Froxlor\FroxlorLogger;
use Froxlor\Validate\Validate;
if ($action == '') {
$action = 'login';
@@ -352,8 +353,7 @@ if ($action == '2fa_entercode') {
$message = sprintf($lng['error']['login_blocked'], Settings::Get('login.deactivatetime'));
break;
case 4:
$cmail = isset($_GET['customermail']) ? $_GET['customermail'] : 'unknown';
$message = str_replace('%s', $cmail, $lng['error']['errorsendingmail']);
$message = $lng['error']['errorsendingmailpub'];
break;
case 5:
$message = $lng['error']['user_banned'];
@@ -425,6 +425,19 @@ if ($action == 'forgotpwd') {
}
}
$no_action = false;
if ($adminchecked) {
if (Settings::Get('panel.allow_preset_admin') != '1') {
$message = $lng['pwdreminder']['notallowed'];
unset($adminchecked);
}
} else {
if (Settings::Get('panel.allow_preset') != '1') {
$message = $lng['pwdreminder']['notallowed'];
}
}
if (empty($message)) {
if ($result_stmt !== null) {
$user = $result_stmt->fetch(PDO::FETCH_ASSOC);
@@ -566,18 +579,8 @@ if ($action == 'forgotpwd') {
unset($user);
}
} else {
$message = $lng['login']['usernotfound'];
}
}
if ($adminchecked) {
if (Settings::Get('panel.allow_preset_admin') != '1') {
$message = $lng['pwdreminder']['notallowed'];
unset($adminchecked);
}
} else {
if (Settings::Get('panel.allow_preset') != '1') {
$message = $lng['pwdreminder']['notallowed'];
}
}

View File

@@ -723,7 +723,7 @@ opcache.validate_timestamps'),
('panel', 'logo_image_login', ''),
('panel', 'logo_overridetheme', '0'),
('panel', 'logo_overridecustom', '0'),
('panel', 'version', '0.10.35.1'),
('panel', 'version', '0.10.38.3'),
('panel', 'db_version', '202112310');

View File

@@ -991,3 +991,33 @@ if (\Froxlor\Froxlor::isFroxlorVersion('0.10.35')) {
showUpdateStep("Updating from 0.10.35 to 0.10.35.1", false);
\Froxlor\Froxlor::updateToVersion('0.10.35.1');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.35.1')) {
showUpdateStep("Updating from 0.10.35.1 to 0.10.36", false);
\Froxlor\Froxlor::updateToVersion('0.10.36');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.36')) {
showUpdateStep("Updating from 0.10.36 to 0.10.37", false);
\Froxlor\Froxlor::updateToVersion('0.10.37');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.37')) {
showUpdateStep("Updating from 0.10.37 to 0.10.38", false);
\Froxlor\Froxlor::updateToVersion('0.10.38');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.38')) {
showUpdateStep("Updating from 0.10.38 to 0.10.38.1", false);
\Froxlor\Froxlor::updateToVersion('0.10.38.1');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.38.1')) {
showUpdateStep("Updating from 0.10.38.1 to 0.10.38.2", false);
\Froxlor\Froxlor::updateToVersion('0.10.38.2');
}
if (\Froxlor\Froxlor::isFroxlorVersion('0.10.38.2')) {
showUpdateStep("Updating from 0.10.38.2 to 0.10.38.3", false);
\Froxlor\Froxlor::updateToVersion('0.10.38.3');
}

View File

@@ -180,12 +180,18 @@ abstract class ApiParameter
*/
private function trimArray($input)
{
if ($input === '') {
return "";
}
if (is_numeric($input) || is_null($input)) {
return $input;
}
if (!is_array($input)) {
return trim($input);
}
return array_map(array(
return array_map([
$this,
'trimArray'
), $input);
], $input);
}
}

View File

@@ -227,7 +227,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$ipaddress = $this->getParam('ipaddress', true, - 1);
// validation
$name = \Froxlor\Validate\Validate::validate($name, 'name', '', '', array(), true);
$name = \Froxlor\Validate\Validate::validate($name, 'name', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$idna_convert = new \Froxlor\Idna\IdnaWrapper();
$email = $idna_convert->encode(\Froxlor\Validate\Validate::validate($email, 'email', '', '', array(), true));
$def_language = \Froxlor\Validate\Validate::validate($def_language, 'default language', '', '', array(), true);
@@ -475,7 +475,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
$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']);
$custom_notes = $this->getParam('custom_notes', true, ($result['custom_notes'] ?? ""));
$custom_notes_show = $this->getBoolParam('custom_notes_show', true, $result['custom_notes_show']);
$theme = $this->getParam('theme', true, $result['theme']);
@@ -527,7 +527,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt
}
// validation
$name = \Froxlor\Validate\Validate::validate($name, 'name', '', '', array(), true);
$name = \Froxlor\Validate\Validate::validate($name, 'name', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$idna_convert = new \Froxlor\Idna\IdnaWrapper();
$email = $idna_convert->encode(\Froxlor\Validate\Validate::validate($email, 'email', '', '', array(), true));
$def_language = \Froxlor\Validate\Validate::validate($def_language, 'default language', '', '', array(), true);

View File

@@ -406,12 +406,12 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
}
// validation
$name = \Froxlor\Validate\Validate::validate($name, 'name', '', '', array(), true);
$firstname = \Froxlor\Validate\Validate::validate($firstname, 'first name', '', '', array(), true);
$company = \Froxlor\Validate\Validate::validate($company, 'company', '', '', array(), true);
$street = \Froxlor\Validate\Validate::validate($street, 'street', '', '', array(), true);
$name = \Froxlor\Validate\Validate::validate($name, 'name', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$firstname = \Froxlor\Validate\Validate::validate($firstname, 'first name', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$company = \Froxlor\Validate\Validate::validate($company, 'company', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$street = \Froxlor\Validate\Validate::validate($street, 'street', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$zipcode = \Froxlor\Validate\Validate::validate($zipcode, 'zipcode', '/^[0-9 \-A-Z]*$/', '', array(), true);
$city = \Froxlor\Validate\Validate::validate($city, 'city', '', '', array(), true);
$city = \Froxlor\Validate\Validate::validate($city, 'city', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$phone = \Froxlor\Validate\Validate::validate($phone, 'phone', '/^[0-9\- \+\(\)\/]*$/', '', array(), true);
$fax = \Froxlor\Validate\Validate::validate($fax, 'fax', '/^[0-9\- \+\(\)\/]*$/', '', array(), true);
$idna_convert = new \Froxlor\Idna\IdnaWrapper();
@@ -1003,12 +1003,12 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
// validation
if ($this->isAdmin()) {
$idna_convert = new \Froxlor\Idna\IdnaWrapper();
$name = \Froxlor\Validate\Validate::validate($name, 'name', '', '', array(), true);
$firstname = \Froxlor\Validate\Validate::validate($firstname, 'first name', '', '', array(), true);
$company = \Froxlor\Validate\Validate::validate($company, 'company', '', '', array(), true);
$street = \Froxlor\Validate\Validate::validate($street, 'street', '', '', array(), true);
$name = \Froxlor\Validate\Validate::validate($name, 'name', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$firstname = \Froxlor\Validate\Validate::validate($firstname, 'first name', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$company = \Froxlor\Validate\Validate::validate($company, 'company', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$street = \Froxlor\Validate\Validate::validate($street, 'street', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$zipcode = \Froxlor\Validate\Validate::validate($zipcode, 'zipcode', '/^[0-9 \-A-Z]*$/', '', array(), true);
$city = \Froxlor\Validate\Validate::validate($city, 'city', '', '', array(), true);
$city = \Froxlor\Validate\Validate::validate($city, 'city', \Froxlor\Validate\Validate::REGEX_DESC_TEXT, '', array(), true);
$phone = \Froxlor\Validate\Validate::validate($phone, 'phone', '/^[0-9\- \+\(\)\/]*$/', '', array(), true);
$fax = \Froxlor\Validate\Validate::validate($fax, 'fax', '/^[0-9\- \+\(\)\/]*$/', '', array(), true);
$email = $idna_convert->encode(\Froxlor\Validate\Validate::validate($email, 'email', '', '', array(), true));

View File

@@ -65,7 +65,7 @@ class EmailForwarders extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
$id = $result['id'];
// current destination array
$result['destination_array'] = explode(' ', $result['destination']);
$result['destination_array'] = explode(' ', ($result['destination'] ?? ''));
// prepare destination
$destination = trim($destination);

View File

@@ -378,9 +378,9 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$listen_statement = $this->getBoolParam('listen_statement', true, $result['listen_statement']);
$namevirtualhost_statement = $this->getBoolParam('namevirtualhost_statement', true, $result['namevirtualhost_statement']);
$vhostcontainer = $this->getBoolParam('vhostcontainer', true, $result['vhostcontainer']);
$specialsettings = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('specialsettings', true, $result['specialsettings'])), 'specialsettings', \Froxlor\Validate\Validate::REGEX_CONF_TEXT, '', array(), true);
$specialsettings = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('specialsettings', true, ($result['specialsettings'] ?? ""))), 'specialsettings', \Froxlor\Validate\Validate::REGEX_CONF_TEXT, '', array(), true);
$vhostcontainer_servername_statement = $this->getParam('vhostcontainer_servername_statement', true, $result['vhostcontainer_servername_statement']);
$default_vhostconf_domain = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('default_vhostconf_domain', true, $result['default_vhostconf_domain'])), 'default_vhostconf_domain', \Froxlor\Validate\Validate::REGEX_CONF_TEXT, '', array(), true);
$default_vhostconf_domain = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('default_vhostconf_domain', true, ($result['default_vhostconf_domain'] ?? ""))), 'default_vhostconf_domain', \Froxlor\Validate\Validate::REGEX_CONF_TEXT, '', array(), true);
$docroot = \Froxlor\Validate\Validate::validate($this->getParam('docroot', true, $result['docroot']), 'docroot', \Froxlor\Validate\Validate::REGEX_DIR, '', array(), true);
if ((int) Settings::Get('system.use_ssl') == 1) {
@@ -389,9 +389,9 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$ssl_key_file = \Froxlor\Validate\Validate::validate($this->getParam('ssl_key_file', $ssl, $result['ssl_key_file']), 'ssl_key_file', '', '', array(), true);
$ssl_ca_file = \Froxlor\Validate\Validate::validate($this->getParam('ssl_ca_file', true, $result['ssl_ca_file']), 'ssl_ca_file', '', '', array(), true);
$ssl_cert_chainfile = \Froxlor\Validate\Validate::validate($this->getParam('ssl_cert_chainfile', true, $result['ssl_cert_chainfile']), 'ssl_cert_chainfile', '', '', array(), true);
$ssl_specialsettings = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('ssl_specialsettings', true, $result['ssl_specialsettings'])), 'ssl_specialsettings', \Froxlor\Validate\Validate::REGEX_CONF_TEXT, '', array(), true);
$ssl_specialsettings = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('ssl_specialsettings', true, ($result['ssl_specialsettings'] ?? ""))), 'ssl_specialsettings', \Froxlor\Validate\Validate::REGEX_CONF_TEXT, '', array(), true);
$include_specialsettings = $this->getBoolParam('include_specialsettings', true, $result['include_specialsettings']);
$ssl_default_vhostconf_domain = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('ssl_default_vhostconf_domain', true, $result['ssl_default_vhostconf_domain'])), 'ssl_default_vhostconf_domain', \Froxlor\Validate\Validate::REGEX_CONF_TEXT, '', array(), true);
$ssl_default_vhostconf_domain = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('ssl_default_vhostconf_domain', true, ($result['ssl_default_vhostconf_domain'] ?? ""))), 'ssl_default_vhostconf_domain', \Froxlor\Validate\Validate::REGEX_CONF_TEXT, '', array(), true);
$include_default_vhostconf_domain = $this->getBoolParam('include_default_vhostconf_domain', true, $result['include_default_vhostconf_domain']);
} else {
$ssl = 0;

View File

@@ -99,7 +99,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
}
// 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');
}

View File

@@ -4,6 +4,7 @@ namespace Froxlor\Cron\System;
use Froxlor\Database\Database;
use Froxlor\Settings;
use Froxlor\FroxlorLogger;
use Froxlor\FileDir;
/**
* This file is part of the Froxlor project.
@@ -150,13 +151,17 @@ class BackupCron extends \Froxlor\Cron\FroxlorCron
$sql_root = Database::getSqlData();
Database::needRoot(false);
$mysqlcnf_file = tempnam("/tmp", "frx");
$mysqlcnf = "[mysqldump]\npassword=".$sql_root['passwd']."\n";
file_put_contents($mysqlcnf_file, $mysqlcnf);
$has_dbs = false;
while ($row = $sel_stmt->fetch()) {
$cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mysqldump -u ' . escapeshellarg($sql_root['user']) . ' -pXXXXX ' . $row['databasename'] . ' > ' . \Froxlor\FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'));
$bool_false = false;
\Froxlor\FileDir::safe_exec('mysqldump -u ' . escapeshellarg($sql_root['user']) . ' -p' . $sql_root['passwd'] . ' ' . $row['databasename'] . ' > ' . \Froxlor\FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'), $bool_false, array(
\Froxlor\FileDir::safe_exec('mysqldump --defaults-file=' . escapeshellarg($mysqlcnf_file) .' -u ' . escapeshellarg($sql_root['user']) . ' ' . $row['databasename'] . ' > ' . FileDir::makeCorrectFile($tmpdir . '/mysql/' . $row['databasename'] . '_' . date('YmdHi', time()) . '.sql'), $bool_false, [
'>'
));
]);
$has_dbs = true;
}
@@ -164,6 +169,8 @@ class BackupCron extends \Froxlor\Cron\FroxlorCron
$create_backup_tar_data .= './mysql ';
}
unlink($mysqlcnf_file);
unset($sql_root);
}

View File

@@ -60,6 +60,7 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
'name' => $row['name'],
'firstname' => $row['firstname'],
'company' => $row['company'],
'loginname' => $row['loginname'],
'customernumber' => $row['customernumber']
);
$replace_arr = array(
@@ -374,6 +375,7 @@ class ReportsCron extends \Froxlor\Cron\FroxlorCron
'name' => $row['name'],
'firstname' => $row['firstname'],
'company' => $row['company'],
'loginname' => $row['loginname'],
'customernumber' => $row['customernumber']
);
$replace_arr = array(

View File

@@ -190,11 +190,17 @@ class Database
*/
public static function getSqlUsernameLength()
{
// MariaDB supports up to 80 characters but only 64 for databases and as we use the loginname also for
// database names, we set the limit to 64 here
if (strpos(strtolower(Database::getAttribute(\PDO::ATTR_SERVER_VERSION)), "mariadb") !== false) {
$mysql_max = 64;
} else {
// MySQL user names can be up to 32 characters long (16 characters before MySQL 5.7.8).
$mysql_max = 32;
if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.8', '<')) {
$mysql_max = 16;
}
}
return $mysql_max;
}

View File

@@ -173,7 +173,10 @@ class DbManager
if (isset($users[$username]) && is_array($users[$username]) && isset($users[$username]['hosts']) && is_array($users[$username]['hosts'])) {
$password = $users[$username]['password'];
$password = [
'password' => $users[$username]['password'],
'plugin' => $users[$username]['plugin']
];
foreach ($mysql_access_host_array as $mysql_access_host) {

View File

@@ -1,4 +1,5 @@
<?php
namespace Froxlor\Database\Manager;
use Froxlor\Database\Database;
@@ -68,7 +69,7 @@ class DbManagerMySQL
* username and sets the password for that user the given access_host
*
* @param string $username
* @param string $password
* @param string|array $password
* @param string $access_host
* @param bool $p_encrypted
* optional, whether the password is encrypted or not, default false
@@ -77,6 +78,12 @@ class DbManagerMySQL
*/
public function grantPrivilegesTo($username = null, $password = null, $access_host = null, $p_encrypted = false, $update = false)
{
$pwd_plugin = 'mysql_native_password';
if (is_array($password) && count($password) == 2) {
$pwd_plugin = $password['plugin'];
$password = $password['password'];
}
if (!$update) {
// create user
if ($p_encrypted) {
@@ -86,7 +93,7 @@ class DbManagerMySQL
");
} else {
$stmt = Database::prepare("
CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED WITH mysql_native_password AS :password
CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED WITH " . $pwd_plugin . " AS :password
");
}
} else {
@@ -115,7 +122,7 @@ class DbManagerMySQL
}
} else {
if ($p_encrypted) {
$stmt = Database::prepare("ALTER USER :username@:host IDENTIFIED WITH mysql_native_password AS :password");
$stmt = Database::prepare("ALTER USER :username@:host IDENTIFIED WITH " . $pwd_plugin . " AS :password");
} else {
$stmt = Database::prepare("ALTER USER :username@:host IDENTIFIED BY :password");
}
@@ -136,7 +143,7 @@ class DbManagerMySQL
*/
public function deleteDatabase($dbname = null)
{
if (Database::getAttribute(\PDO::ATTR_SERVER_VERSION) < '5.0.2') {
if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.0.2', '<')) {
// failsafe if user has been deleted manually (requires MySQL 4.1.2+)
$stmt = Database::prepare("REVOKE ALL PRIVILEGES, GRANT OPTION FROM `" . $dbname . "`");
Database::pexecute($stmt, array(), false);
@@ -250,6 +257,7 @@ class DbManagerMySQL
if (!isset($allsqlusers[$row['User']]) || !is_array($allsqlusers[$row['User']])) {
$allsqlusers[$row['User']] = array(
'password' => $row['Password'] ?? $row['authentication_string'],
'plugin' => $row['plugin'] ?? 'mysql_native_password',
'hosts' => array()
);
}

View File

@@ -1,4 +1,5 @@
<?php
namespace Froxlor;
use Froxlor\Database\Database;
@@ -408,7 +409,6 @@ class FileDir
natcasesort($dirList);
if (sizeof($dirList) > 0) {
if (sizeof($dirList) <= 100) {
$_field = '';
foreach ($dirList as $dir) {
if (strpos($dir, $path) === 0) {
@@ -425,17 +425,6 @@ class FileDir
'type' => 'select',
'value' => $_field
);
} else {
// remove starting slash we added
// for the Dropdown, #225
$value = substr($value, 1);
// $field = $lng['panel']['toomanydirs'];
$field = array(
'type' => 'text',
'value' => htmlspecialchars($value),
'note' => $lng['panel']['toomanydirs']
);
}
} else {
// $field = $lng['panel']['dirsmissing'];
// $field = '<input type="hidden" name="path" value="/" />';
@@ -489,22 +478,31 @@ class FileDir
$filter = function ($file, $key, $iterator) use ($exclude) {
if (in_array($file->getFilename(), $exclude)) {
return false;
} elseif (substr($file->getFilename(), 0, 1) == '.') {
// also hide hidden folders
return false;
}
return true;
};
// create RecursiveIteratorIterator
$its = new \RecursiveIteratorIterator(new \RecursiveCallbackFilterIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), $filter));
$its = new \RecursiveIteratorIterator(
new \RecursiveCallbackFilterIterator(
new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS),
$filter
),
\RecursiveIteratorIterator::SELF_FIRST,
\RecursiveIteratorIterator::CATCH_GET_CHILD
);
// 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
// @TODO
// $its->setMaxDepth(2);
$its->setMaxDepth(2);
// check every file
foreach ($its as $fullFileName => $it) {
if ($it->isDir() && (fileowner($fullFileName) == $uid || filegroup($fullFileName) == $gid)) {
$_fileList[] = self::makeCorrectDir(dirname($fullFileName));
$_fileList[] = self::makeCorrectDir($fullFileName);
}
}
$_fileList[] = $path;

View File

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

View File

@@ -1,4 +1,5 @@
<?php
namespace Froxlor\Settings;
use Froxlor\Database\Database;
@@ -391,8 +392,18 @@ class Store
}
// Make sure mime-type matches an image
if (!in_array(mime_content_type($_FILES[$fieldname]['tmp_name']), ['image/jpeg','image/jpg','image/png','image/gif'])) {
throw new \Exception("Uploaded file not a valid image");
if (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $_FILES[$fieldname]['tmp_name']);
finfo_close($finfo);
} else {
$mimetype = mime_content_type($_FILES[$fieldname]['tmp_name']);
}
if (empty($mimetype)) {
$mimetype = 'application/octet-stream';
}
if (!in_array($mimetype, ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
throw new \Exception("Uploaded file is not a valid image");
}
// Determine file extension
@@ -400,6 +411,15 @@ class Store
$file_extension = strtolower(array_pop($spl));
unset($spl);
if (!in_array($file_extension, [
'jpeg',
'jpg',
'png',
'gif'
])) {
throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif");
}
// Move file
if (!move_uploaded_file($_FILES[$fieldname]['tmp_name'], $path . $fielddata['image_name'] . '.' . $file_extension)) {
throw new \Exception("Unable to save image to img folder");

View File

@@ -3561,7 +3561,7 @@ postmaster_address = postmaster@<SERVERNAME>
protocol lda {
# Space separated list of plugins to load (default is global mail_plugins).
#mail_plugins = $mail_plugins
mail_plugins = $mail_plugins quota sieve
}
]]>
</content>

View File

@@ -3557,7 +3557,7 @@ postmaster_address = postmaster@<SERVERNAME>
protocol lda {
# Space separated list of plugins to load (default is global mail_plugins).
#mail_plugins = $mail_plugins
mail_plugins = $mail_plugins quota sieve
}
]]>
</content>

View File

@@ -59,7 +59,7 @@ header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time()));
// Inline-JS is no longer allowed and used
// See: http://people.mozilla.org/~bsterne/content-security-policy/index.html
// New stuff see: https://www.owasp.org/index.php/List_of_useful_HTTP_headers and https://www.owasp.org/index.php/Content_Security_Policy
$csp_content = "default-src 'self'; script-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self';";
$csp_content = "default-src 'self'; script-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; object-src 'self'; frame-src 'self'; frame-ancestors 'self';";
header("Content-Security-Policy: " . $csp_content);
header("X-Content-Security-Policy: " . $csp_content);
header("X-WebKit-CSP: " . $csp_content);

View File

@@ -678,6 +678,7 @@ $lng['admin']['message'] = 'Write a Message';
$lng['admin']['text'] = 'Message';
$lng['menu']['message'] = 'Messages';
$lng['error']['errorsendingmail'] = 'The message to "%s" failed';
$lng['error']['errorsendingmailpub'] = 'The message to the given email-address failed';
$lng['error']['cannotreaddir'] = 'Unable to read directory "%s"';
$lng['message']['success'] = 'Successfully sent message to %s recipients';
$lng['message']['norecipients'] = 'No e-mail has been sent because there are no recipients in the database';
@@ -765,7 +766,7 @@ $lng['pwdreminder']['success'] = 'Password reset successfully requested. Please
// ADDED IN 1.2.19-svn18
$lng['serversettings']['allow_password_reset']['title'] = 'Allow password reset by customers';
$lng['pwdreminder']['notallowed'] = 'Password reset is disabled';
$lng['pwdreminder']['notallowed'] = 'Unknown user or password reset is disabled';
// ADDED IN 1.2.19-svn21
@@ -2143,3 +2144,8 @@ $lng['serversettings']['phpfpm_settings']['allow_all_customers']['description']
$lng['error']['pathmustberelative'] = 'The user does not have the permission to specify directories outside the customers home-directory. Please specify a relative path (no leading /).';
$lng['serversettings']['acmeshpath']['title'] = 'Path to acme.sh';
$lng['serversettings']['acmeshpath']['description'] = 'Set this to where acme.sh is installed to, including the acme.sh script<br>Default is <b>/root/.acme.sh/acme.sh</b>';
$lng['question']['api_reallydelete'] = 'Do you really want to delete the api-key?';
$lng['question']['api_reallyadd'] = 'Do you really want to create a new api-key?';
$lng['question']['dnsentry_reallydelete'] = 'Do you really want to delete the dns entry?';
$lng['question']['certificate_reallydelete'] = 'Do you really want to delete the certificate?';

View File

@@ -671,6 +671,7 @@ $lng['admin']['message'] = 'Rundmail senden';
$lng['admin']['text'] = 'Nachricht';
$lng['menu']['message'] = 'Nachrichten';
$lng['error']['errorsendingmail'] = 'Das Versenden der Nachricht an "%s" schlug fehl.';
$lng['error']['errorsendingmailpub'] = 'Das Versenden der Nachricht an die angegebene E-Mail Adresse schlug fehl.';
$lng['error']['cannotreaddir'] = 'Der Ordner "%s" kann nicht gelesen werden';
$lng['message']['success'] = 'Nachricht erfolgreich an "%s" Empfänger gesendet';
$lng['message']['norecipients'] = 'Es wurde keine E-Mail versendet, da sich keine Empfänger in der Datenbank befinden';
@@ -758,7 +759,7 @@ $lng['pwdreminder']['success'] = 'Das Zurücksetzen des Passworts wurde erfolgre
// ADDED IN 1.2.19-svn18
$lng['serversettings']['allow_password_reset']['title'] = 'Erlaube das Zurücksetzen des Kundenpassworts.';
$lng['pwdreminder']['notallowed'] = 'Das Zurücksetzen des Passworts ist deaktiviert.';
$lng['pwdreminder']['notallowed'] = 'Unbekannter Benutzer oder Zurücksetzen des Passworts ist deaktiviert.';
// ADDED IN 1.2.19-svn21
@@ -1789,3 +1790,8 @@ $lng['serversettings']['phpfpm_settings']['allow_all_customers']['description']
$lng['error']['pathmustberelative'] = 'Der Benutzer hat nicht die benötigten Berechtigungen, um Pfade außerhalb des Kunden-Heimatverzeichnisses anzugeben. Bitte einen relativen Pfad angeben (kein führendes /).';
$lng['serversettings']['acmeshpath']['title'] = 'Pfad zu acme.sh';
$lng['serversettings']['acmeshpath']['description'] = 'Installationspfad zu acme.sh, inklusive acme.sh Script<br>Standard ist <b>/root/.acme.sh/acme.sh</b>';
$lng['question']['api_reallydelete'] = 'Api-Key wirklich löschen?';
$lng['question']['api_reallyadd'] = 'Einen neuen Api-Key erstellen?';
$lng['question']['dnsentry_reallydelete'] = 'Zonen-Eintrag wirklich löschen?';
$lng['question']['certificate_reallydelete'] = 'Zertifikat wirklich löschen?';

View File

@@ -29,8 +29,9 @@ $success_message = "";
// do the delete and then just show a success-message and the certificates list again
if ($action == 'delete') {
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
$id = isset($_POST['id']) ? (int) $_POST['id'] : (isset($_GET['id']) ? (int) $_GET['id'] : 0);
if ($id > 0) {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
$json_result = Certificates::getLocal($userinfo, array(
'id' => $id
@@ -39,6 +40,13 @@ if ($action == 'delete') {
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
} else {
\Froxlor\UI\HTML::askYesNo('certificate_reallydelete', $filename, array(
'page' => $page,
'action' => $action,
'id' => $id
), $id);
}
}
}

View File

@@ -82,6 +82,7 @@ header img {
.login header img {
margin: 0 auto;
display: block;
max-width: calc(100% - 20px);
}
img.small {

View File

@@ -198,7 +198,7 @@ class ValidateTest extends TestCase
$result = Validate::validateUsername('web123sql2', true, $mysql_max);
$this->assertTrue($result);
// too long
$result = Validate::validateUsername('myperfectsuperduperwebuser123sql2', true, $mysql_max);
$result = Validate::validateUsername('myperfectsuperduperwebuserwhosnameisenormouslylongandprettyandshouldinnowaybeaccepted123sql2', true, $mysql_max);
$this->assertFalse($result);
// not unix-conform
$result = Validate::validateUsername('web123-sql2', true, $mysql_max);

View File

@@ -286,8 +286,8 @@ class MysqlsTest extends TestCase
$dbm = new \Froxlor\Database\DbManager(\Froxlor\FroxlorLogger::getInstanceOf());
$users = $dbm->getManager()->getAllSqlUsers(false);
foreach ($users as $user => $data) {
if (TRAVIS_CI == 1 && strtolower($user) == 'mariadb.sys') {
// travis seems to have a user for mariadb on version 10.4
if (strtolower($user) == 'mariadb.sys') {
// some systems seem to have a user for mariadb on version 10.4
// we do not want to test that one
continue;
}
@@ -302,7 +302,11 @@ class MysqlsTest extends TestCase
// grant privileges to another host
$testdata = $users['froxlor010'];
$dbm->getManager()->grantPrivilegesTo('froxlor010', $testdata['password'], '10.0.0.10', true);
$password = [
'password' => $testdata['password'],
'plugin' => $testdata['plugin']
];
$dbm->getManager()->grantPrivilegesTo('froxlor010', $password, '10.0.0.10', true);
// select all entries from mysql.user for froxlor010 to compare password-hashes
$sel_stmt = Database::prepare("SELECT * FROM mysql.user WHERE `User` = :usr");