diff --git a/api_keys.php b/api_keys.php index 1a110ce4..f1bec666 100644 --- a/api_keys.php +++ b/api_keys.php @@ -1,5 +1,5 @@ 0) { - $chk = (AREA == 'admin' && $userinfo['customers_see_all'] == '1') ? true : false; - if (AREA == 'customer') { - $chk_stmt = Database::prepare(" - SELECT c.customerid FROM `" . TABLE_PANEL_CUSTOMERS . "` c - LEFT JOIN `" . TABLE_API_KEYS . "` ak ON ak.customerid = c.customerid - WHERE ak.`id` = :id AND c.`customerid` = :cid - "); - $chk = Database::pexecute_first($chk_stmt, array( - 'id' => $id, - 'cid' => $userinfo['customerid'] - )); - } elseif (AREA == 'admin' && $userinfo['customers_see_all'] == '0') { - $chk_stmt = Database::prepare(" - SELECT a.adminid FROM `" . TABLE_PANEL_ADMINS . "` a - LEFT JOIN `" . TABLE_API_KEYS . "` ak ON ak.adminid = a.adminid - WHERE ak.`id` = :id AND a.`adminid` = :aid - "); - $chk = Database::pexecute_first($chk_stmt, array( - 'id' => $id, - 'aid' => $userinfo['adminid'] - )); - } - if ($chk !== false) { - Database::pexecute($del_stmt, array( + if (isset($_POST['send']) && $_POST['send'] == 'send') { + $chk = (AREA == 'admin' && $userinfo['customers_see_all'] == '1') ? true : false; + if (AREA == 'customer') { + $chk_stmt = Database::prepare(" + SELECT c.customerid FROM `" . TABLE_PANEL_CUSTOMERS . "` c + LEFT JOIN `" . TABLE_API_KEYS . "` ak ON ak.customerid = c.customerid + WHERE ak.`id` = :id AND c.`customerid` = :cid + "); + $chk = Database::pexecute_first($chk_stmt, array( + 'id' => $id, + 'cid' => $userinfo['customerid'] + )); + } elseif (AREA == 'admin' && $userinfo['customers_see_all'] == '0') { + $chk_stmt = Database::prepare(" + SELECT a.adminid FROM `" . TABLE_PANEL_ADMINS . "` a + LEFT JOIN `" . TABLE_API_KEYS . "` ak ON ak.adminid = a.adminid + WHERE ak.`id` = :id AND a.`adminid` = :aid + "); + $chk = Database::pexecute_first($chk_stmt, array( + 'id' => $id, + 'aid' => $userinfo['adminid'] + )); + } + if ($chk !== false) { + Database::pexecute($del_stmt, array( + 'id' => $id + )); + $success_message = sprintf($lng['apikeys']['apikey_removed'], $id); + } + } else { + \Froxlor\UI\HTML::askYesNo('api_reallydelete', $filename, array( + 'page' => $page, + 'action' => $action, 'id' => $id - )); - $success_message = sprintf($lng['apikeys']['apikey_removed'], $id); + ), $id); } } } elseif ($action == 'add') { - $ins_stmt = Database::prepare(" - INSERT INTO `" . TABLE_API_KEYS . "` SET - `apikey` = :key, `secret` = :secret, `adminid` = :aid, `customerid` = :cid, `valid_until` = '-1', `allowed_from` = '' - "); - // customer generates for himself, admins will see a customer-select-box later - if (AREA == 'admin') { - $cid = 0; - } elseif (AREA == 'customer') { - $cid = $userinfo['customerid']; + + 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` = '' + "); + // customer generates for himself, admins will see a customer-select-box later + if (AREA == 'admin') { + $cid = 0; + } elseif (AREA == 'customer') { + $cid = $userinfo['customerid']; + } + $key = hash('sha256', openssl_random_pseudo_bytes(64 * 64)); + $secret = hash('sha512', openssl_random_pseudo_bytes(64 * 64 * 4)); + Database::pexecute($ins_stmt, array( + 'key' => $key, + 'secret' => $secret, + 'aid' => $userinfo['adminid'], + 'cid' => $cid + )); + $success_message = $lng['apikeys']['apikey_added']; + } else { + \Froxlor\UI\HTML::askYesNo('api_reallyadd', $filename, array( + 'page' => $page, + 'action' => $action + ), $id); } - $key = hash('sha256', openssl_random_pseudo_bytes(64 * 64)); - $secret = hash('sha512', openssl_random_pseudo_bytes(64 * 64 * 4)); - Database::pexecute($ins_stmt, array( - 'key' => $key, - 'secret' => $secret, - 'aid' => $userinfo['adminid'], - 'cid' => $cid - )); - $success_message = $lng['apikeys']['apikey_added']; } 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; + $valid_until = isset($_POST['valid_until']) ? (int) $_POST['valid_until'] : -1; // validate allowed_from - if (! empty($allowed_from)) { + if (!empty($allowed_from)) { $ip_list = array_map('trim', explode(",", $allowed_from)); $_check_list = $ip_list; foreach ($_check_list as $idx => $ip) { @@ -100,8 +120,8 @@ if ($action == 'delete') { $allowed_from = implode(",", array_unique($ip_list)); } - if ($valid_until <= 0 || ! is_numeric($valid_until)) { - $valid_until = - 1; + if ($valid_until <= 0 || !is_numeric($valid_until)) { + $valid_until = -1; } $upd_stmt = Database::prepare(" diff --git a/dns_editor.php b/dns_editor.php index a5d25eac..da10f5cd 100644 --- a/dns_editor.php +++ b/dns_editor.php @@ -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,17 +56,25 @@ if ($action == 'add_record' && ! empty($_POST)) { } } elseif ($action == 'delete') { // remove entry - $entry_id = isset($_GET['id']) ? (int) $_GET['id'] : 0; - if ($entry_id > 0) { - try { - DomainZones::getLocal($userinfo, array( - 'entry_id' => $entry_id, - 'id' => $domain_id - ))->delete(); - // success message (inline) - $success_message = $lng['success']['dns_record_deleted']; - } catch (Exception $e) { - $errors = str_replace("\n", "
", $e->getMessage()); + if ($id > 0) { + if (isset($_POST['send']) && $_POST['send'] == 'send') { + try { + DomainZones::getLocal($userinfo, array( + 'entry_id' => $id, + 'id' => $domain_id + ))->delete(); + // success message (inline) + $success_message = $lng['success']['dns_record_deleted']; + } catch (Exception $e) { + $errors = str_replace("\n", "
", $e->getMessage()); + } + } else { + \Froxlor\UI\HTML::askYesNo('dnsentry_reallydelete', $filename, array( + 'page' => $page, + 'action' => $action, + 'id' => $id, + 'domain_id' => $domain_id + ), $id); } } } diff --git a/index.php b/index.php index 07a96e82..6e2caa5b 100644 --- a/index.php +++ b/index.php @@ -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,159 +425,162 @@ if ($action == 'forgotpwd') { } } - if ($result_stmt !== null) { - $user = $result_stmt->fetch(PDO::FETCH_ASSOC); - - /* Check whether user is banned */ - if ($user['deactivated']) { - \Froxlor\UI\Response::redirectTo('index.php', array( - 'showmessage' => '8' - )); - exit(); + $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 (($adminchecked && Settings::Get('panel.allow_preset_admin') == '1') || $adminchecked == false) { - if ($user !== false) { - // build a activation code - $timestamp = time(); - $first = substr(md5($user['loginname'] . $timestamp . \Froxlor\PhpHelper::randomStr(16)), 0, 15); - $third = substr(md5($user['email'] . $timestamp . \Froxlor\PhpHelper::randomStr(16)), - 15); - $activationcode = $first . $timestamp . $third . substr(md5($third . $timestamp), 0, 10); + if (empty($message)) { + if ($result_stmt !== null) { + $user = $result_stmt->fetch(PDO::FETCH_ASSOC); - // Drop all existing activation codes for this user - $stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_ACTIVATION . "` - WHERE `userid` = :userid - AND `admin` = :admin"); - $params = array( - "userid" => $adminchecked ? $user['adminid'] : $user['customerid'], - "admin" => $adminchecked ? 1 : 0 - ); - Database::pexecute($stmt, $params); - - // Add new activation code to database - $stmt = Database::prepare("INSERT INTO `" . TABLE_PANEL_ACTIVATION . "` - (userid, admin, creation, activationcode) - VALUES (:userid, :admin, :creation, :activationcode)"); - $params = array( - "userid" => $adminchecked ? $user['adminid'] : $user['customerid'], - "admin" => $adminchecked ? 1 : 0, - "creation" => $timestamp, - "activationcode" => $activationcode - ); - Database::pexecute($stmt, $params); - - $rstlog = FroxlorLogger::getInstanceOf(array( - 'loginname' => 'password_reset' + /* Check whether user is banned */ + if ($user['deactivated']) { + \Froxlor\UI\Response::redirectTo('index.php', array( + 'showmessage' => '8' )); - $rstlog->logAction(\Froxlor\FroxlorLogger::USR_ACTION, LOG_WARNING, "User '" . $user['loginname'] . "' requested a link for setting a new password."); + exit(); + } - // Set together our activation link - $protocol = empty($_SERVER['HTTPS']) ? 'http' : 'https'; - // this can be a fixed value to avoid potential exploiting by modifying headers - $host = Settings::Get('system.hostname'); // $_SERVER['HTTP_HOST']; - $port = $_SERVER['SERVER_PORT'] != 80 ? ':' . $_SERVER['SERVER_PORT'] : ''; - // don't add :443 when https is used, as it is default (and just looks weird!) - if ($protocol == 'https' && $_SERVER['SERVER_PORT'] == '443') { - $port = ''; - } - // there can be only one script to handle this so we can use a fixed value here - $script = "/index.php"; // $_SERVER['SCRIPT_NAME']; - if (Settings::Get('system.froxlordirectlyviahostname') == 0) { - $script = \Froxlor\FileDir::makeCorrectFile("/" . basename(__DIR__) . "/" . $script); - } - $activationlink = $protocol . '://' . $host . $port . $script . '?action=resetpwd&resetcode=' . $activationcode; + if (($adminchecked && Settings::Get('panel.allow_preset_admin') == '1') || $adminchecked == false) { + if ($user !== false) { + // build a activation code + $timestamp = time(); + $first = substr(md5($user['loginname'] . $timestamp . \Froxlor\PhpHelper::randomStr(16)), 0, 15); + $third = substr(md5($user['email'] . $timestamp . \Froxlor\PhpHelper::randomStr(16)), - 15); + $activationcode = $first . $timestamp . $third . substr(md5($third . $timestamp), 0, 10); - $replace_arr = array( - 'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($user), - 'NAME' => $user['name'], - 'FIRSTNAME' => $user['firstname'] ?? "", - 'COMPANY' => $user['company'] ?? "", - 'CUSTOMER_NO' => $user['customernumber'] ?? 0, - 'USERNAME' => $loginname, - 'LINK' => $activationlink - ); + // Drop all existing activation codes for this user + $stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_ACTIVATION . "` + WHERE `userid` = :userid + AND `admin` = :admin"); + $params = array( + "userid" => $adminchecked ? $user['adminid'] : $user['customerid'], + "admin" => $adminchecked ? 1 : 0 + ); + Database::pexecute($stmt, $params); - $def_language = ($user['def_language'] != '') ? $user['def_language'] : Settings::Get('panel.standardlanguage'); - $result_stmt = Database::prepare('SELECT `value` FROM `' . TABLE_PANEL_TEMPLATES . '` - WHERE `adminid`= :adminid - AND `language`= :lang - AND `templategroup`=\'mails\' - AND `varname`=\'password_reset_subject\''); - Database::pexecute($result_stmt, array( - "adminid" => $user['adminid'], - "lang" => $def_language - )); - $result = $result_stmt->fetch(PDO::FETCH_ASSOC); - $mail_subject = html_entity_decode(\Froxlor\PhpHelper::replaceVariables((($result['value'] != '') ? $result['value'] : $lng['mails']['password_reset']['subject']), $replace_arr)); + // Add new activation code to database + $stmt = Database::prepare("INSERT INTO `" . TABLE_PANEL_ACTIVATION . "` + (userid, admin, creation, activationcode) + VALUES (:userid, :admin, :creation, :activationcode)"); + $params = array( + "userid" => $adminchecked ? $user['adminid'] : $user['customerid'], + "admin" => $adminchecked ? 1 : 0, + "creation" => $timestamp, + "activationcode" => $activationcode + ); + Database::pexecute($stmt, $params); - $result_stmt = Database::prepare('SELECT `value` FROM `' . TABLE_PANEL_TEMPLATES . '` - WHERE `adminid`= :adminid - AND `language`= :lang - AND `templategroup`=\'mails\' - AND `varname`=\'password_reset_mailbody\''); - Database::pexecute($result_stmt, array( - "adminid" => $user['adminid'], - "lang" => $def_language - )); - $result = $result_stmt->fetch(PDO::FETCH_ASSOC); - $mail_body = html_entity_decode(\Froxlor\PhpHelper::replaceVariables((($result['value'] != '') ? $result['value'] : $lng['mails']['password_reset']['mailbody']), $replace_arr)); - - $_mailerror = false; - $mailerr_msg = ""; - try { - $mail->Subject = $mail_subject; - $mail->AltBody = $mail_body; - $mail->MsgHTML(str_replace("\n", "
", $mail_body)); - $mail->AddAddress($user['email'], \Froxlor\User::getCorrectUserSalutation($user)); - $mail->Send(); - } catch (\PHPMailer\PHPMailer\Exception $e) { - $mailerr_msg = $e->errorMessage(); - $_mailerror = true; - } catch (Exception $e) { - $mailerr_msg = $e->getMessage(); - $_mailerror = true; - } - - if ($_mailerror) { $rstlog = FroxlorLogger::getInstanceOf(array( 'loginname' => 'password_reset' )); - $rstlog->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_ERR, "Error sending mail: " . $mailerr_msg); + $rstlog->logAction(\Froxlor\FroxlorLogger::USR_ACTION, LOG_WARNING, "User '" . $user['loginname'] . "' requested a link for setting a new password."); + + // Set together our activation link + $protocol = empty($_SERVER['HTTPS']) ? 'http' : 'https'; + // this can be a fixed value to avoid potential exploiting by modifying headers + $host = Settings::Get('system.hostname'); // $_SERVER['HTTP_HOST']; + $port = $_SERVER['SERVER_PORT'] != 80 ? ':' . $_SERVER['SERVER_PORT'] : ''; + // don't add :443 when https is used, as it is default (and just looks weird!) + if ($protocol == 'https' && $_SERVER['SERVER_PORT'] == '443') { + $port = ''; + } + // there can be only one script to handle this so we can use a fixed value here + $script = "/index.php"; // $_SERVER['SCRIPT_NAME']; + if (Settings::Get('system.froxlordirectlyviahostname') == 0) { + $script = \Froxlor\FileDir::makeCorrectFile("/" . basename(__DIR__) . "/" . $script); + } + $activationlink = $protocol . '://' . $host . $port . $script . '?action=resetpwd&resetcode=' . $activationcode; + + $replace_arr = array( + 'SALUTATION' => \Froxlor\User::getCorrectUserSalutation($user), + 'NAME' => $user['name'], + 'FIRSTNAME' => $user['firstname'] ?? "", + 'COMPANY' => $user['company'] ?? "", + 'CUSTOMER_NO' => $user['customernumber'] ?? 0, + 'USERNAME' => $loginname, + 'LINK' => $activationlink + ); + + $def_language = ($user['def_language'] != '') ? $user['def_language'] : Settings::Get('panel.standardlanguage'); + $result_stmt = Database::prepare('SELECT `value` FROM `' . TABLE_PANEL_TEMPLATES . '` + WHERE `adminid`= :adminid + AND `language`= :lang + AND `templategroup`=\'mails\' + AND `varname`=\'password_reset_subject\''); + Database::pexecute($result_stmt, array( + "adminid" => $user['adminid'], + "lang" => $def_language + )); + $result = $result_stmt->fetch(PDO::FETCH_ASSOC); + $mail_subject = html_entity_decode(\Froxlor\PhpHelper::replaceVariables((($result['value'] != '') ? $result['value'] : $lng['mails']['password_reset']['subject']), $replace_arr)); + + $result_stmt = Database::prepare('SELECT `value` FROM `' . TABLE_PANEL_TEMPLATES . '` + WHERE `adminid`= :adminid + AND `language`= :lang + AND `templategroup`=\'mails\' + AND `varname`=\'password_reset_mailbody\''); + Database::pexecute($result_stmt, array( + "adminid" => $user['adminid'], + "lang" => $def_language + )); + $result = $result_stmt->fetch(PDO::FETCH_ASSOC); + $mail_body = html_entity_decode(\Froxlor\PhpHelper::replaceVariables((($result['value'] != '') ? $result['value'] : $lng['mails']['password_reset']['mailbody']), $replace_arr)); + + $_mailerror = false; + $mailerr_msg = ""; + try { + $mail->Subject = $mail_subject; + $mail->AltBody = $mail_body; + $mail->MsgHTML(str_replace("\n", "
", $mail_body)); + $mail->AddAddress($user['email'], \Froxlor\User::getCorrectUserSalutation($user)); + $mail->Send(); + } catch (\PHPMailer\PHPMailer\Exception $e) { + $mailerr_msg = $e->errorMessage(); + $_mailerror = true; + } catch (Exception $e) { + $mailerr_msg = $e->getMessage(); + $_mailerror = true; + } + + if ($_mailerror) { + $rstlog = FroxlorLogger::getInstanceOf(array( + 'loginname' => 'password_reset' + )); + $rstlog->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_ERR, "Error sending mail: " . $mailerr_msg); + \Froxlor\UI\Response::redirectTo('index.php', array( + 'showmessage' => '4', + 'customermail' => $user['email'] + )); + exit(); + } + + $mail->ClearAddresses(); \Froxlor\UI\Response::redirectTo('index.php', array( - 'showmessage' => '4', - 'customermail' => $user['email'] + 'showmessage' => '1' )); exit(); + } else { + $rstlog = FroxlorLogger::getInstanceOf(array( + 'loginname' => 'password_reset' + )); + $rstlog->logAction(\Froxlor\FroxlorLogger::USR_ACTION, LOG_WARNING, "User '" . $loginname . "' requested to set a new password, but was not found in database!"); + $message = $lng['login']['combination_not_found']; } - $mail->ClearAddresses(); - \Froxlor\UI\Response::redirectTo('index.php', array( - 'showmessage' => '1' - )); - exit(); - } else { - $rstlog = FroxlorLogger::getInstanceOf(array( - 'loginname' => 'password_reset' - )); - $rstlog->logAction(\Froxlor\FroxlorLogger::USR_ACTION, LOG_WARNING, "User '" . $loginname . "' requested to set a new password, but was not found in database!"); - $message = $lng['login']['combination_not_found']; + unset($user); } - - unset($user); + } else { + $message = $lng['pwdreminder']['notallowed']; } - } 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']; } } diff --git a/install/froxlor.sql b/install/froxlor.sql index c8aef3e6..02f56721 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -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'); diff --git a/install/updates/froxlor/0.10/update_0.10.inc.php b/install/updates/froxlor/0.10/update_0.10.inc.php index 04f30612..8fe7e91a 100644 --- a/install/updates/froxlor/0.10/update_0.10.inc.php +++ b/install/updates/froxlor/0.10/update_0.10.inc.php @@ -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'); +} diff --git a/lib/Froxlor/Api/ApiParameter.php b/lib/Froxlor/Api/ApiParameter.php index 6acb2309..7c4b3dee 100644 --- a/lib/Froxlor/Api/ApiParameter.php +++ b/lib/Froxlor/Api/ApiParameter.php @@ -180,12 +180,18 @@ abstract class ApiParameter */ private function trimArray($input) { - if (! is_array($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); } } diff --git a/lib/Froxlor/Api/Commands/Admins.php b/lib/Froxlor/Api/Commands/Admins.php index 0d39e53c..c3bef132 100644 --- a/lib/Froxlor/Api/Commands/Admins.php +++ b/lib/Froxlor/Api/Commands/Admins.php @@ -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); diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index b4e7e4aa..3cde007d 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -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)); diff --git a/lib/Froxlor/Api/Commands/EmailForwarders.php b/lib/Froxlor/Api/Commands/EmailForwarders.php index 847bf9f6..48f37378 100644 --- a/lib/Froxlor/Api/Commands/EmailForwarders.php +++ b/lib/Froxlor/Api/Commands/EmailForwarders.php @@ -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); diff --git a/lib/Froxlor/Api/Commands/IpsAndPorts.php b/lib/Froxlor/Api/Commands/IpsAndPorts.php index 71d836fb..5afdf8a7 100644 --- a/lib/Froxlor/Api/Commands/IpsAndPorts.php +++ b/lib/Froxlor/Api/Commands/IpsAndPorts.php @@ -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; diff --git a/lib/Froxlor/Api/Commands/PhpSettings.php b/lib/Froxlor/Api/Commands/PhpSettings.php index ae59726f..78299b5c 100644 --- a/lib/Froxlor/Api/Commands/PhpSettings.php +++ b/lib/Froxlor/Api/Commands/PhpSettings.php @@ -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'); } diff --git a/lib/Froxlor/Cron/System/BackupCron.php b/lib/Froxlor/Cron/System/BackupCron.php index 899e7717..b58de0a6 100644 --- a/lib/Froxlor/Cron/System/BackupCron.php +++ b/lib/Froxlor/Cron/System/BackupCron.php @@ -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); } diff --git a/lib/Froxlor/Cron/Traffic/ReportsCron.php b/lib/Froxlor/Cron/Traffic/ReportsCron.php index 852c26f7..c46c5d83 100644 --- a/lib/Froxlor/Cron/Traffic/ReportsCron.php +++ b/lib/Froxlor/Cron/Traffic/ReportsCron.php @@ -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( diff --git a/lib/Froxlor/Database/Database.php b/lib/Froxlor/Database/Database.php index 5235cf11..5580144f 100644 --- a/lib/Froxlor/Database/Database.php +++ b/lib/Froxlor/Database/Database.php @@ -190,10 +190,16 @@ class Database */ public static function getSqlUsernameLength() { - // 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; + // 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; } diff --git a/lib/Froxlor/Database/DbManager.php b/lib/Froxlor/Database/DbManager.php index dc0f3d1b..970c0216 100644 --- a/lib/Froxlor/Database/DbManager.php +++ b/lib/Froxlor/Database/DbManager.php @@ -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) { diff --git a/lib/Froxlor/Database/Manager/DbManagerMySQL.php b/lib/Froxlor/Database/Manager/DbManagerMySQL.php index bf2f01ca..a93d5ef1 100644 --- a/lib/Froxlor/Database/Manager/DbManagerMySQL.php +++ b/lib/Froxlor/Database/Manager/DbManagerMySQL.php @@ -1,4 +1,5 @@ fetch(\PDO::FETCH_ASSOC)) { if ($user_only == false) { - if (! isset($allsqlusers[$row['User']]) || ! is_array($allsqlusers[$row['User']])) { + 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() ); } diff --git a/lib/Froxlor/FileDir.php b/lib/Froxlor/FileDir.php index f71e5b7c..d258835d 100644 --- a/lib/Froxlor/FileDir.php +++ b/lib/Froxlor/FileDir.php @@ -1,4 +1,5 @@ 0) { $dir = trim($dir); - if (substr($dir, - 1, 1) != '/') { + if (substr($dir, -1, 1) != '/') { $dir .= '/'; } if (substr($dir, 0, 1) != '/') { @@ -355,7 +356,7 @@ class FileDir $destination = substr($destination, 1); } - if (substr($destination, - 1, 1) == ' ') { + if (substr($destination, -1, 1) == ' ') { $destination = substr($destination, 0, strlen($destination) - 1); } @@ -390,7 +391,7 @@ class FileDir // but dirList holds the paths with starting slash // so we just add one here to get the correct // default path selected, #225 - if (substr($value, 0, 1) != '/' && ! $dom) { + if (substr($value, 0, 1) != '/' && !$dom) { $value = '/' . $value; } @@ -408,34 +409,22 @@ class FileDir natcasesort($dirList); if (sizeof($dirList) > 0) { - if (sizeof($dirList) <= 100) { - $_field = ''; - foreach ($dirList as $dir) { - if (strpos($dir, $path) === 0) { - $dir = substr($dir, strlen($path)); - // docroot cut off of current directory == empty -> directory is the docroot - if (empty($dir)) { - $dir = '/'; - } - $dir = self::makeCorrectDir($dir); + $_field = ''; + foreach ($dirList as $dir) { + if (strpos($dir, $path) === 0) { + $dir = substr($dir, strlen($path)); + // docroot cut off of current directory == empty -> directory is the docroot + if (empty($dir)) { + $dir = '/'; } - $_field .= \Froxlor\UI\HTML::makeoption($dir, $dir, $value); + $dir = self::makeCorrectDir($dir); } - $field = array( - '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'] - ); + $_field .= \Froxlor\UI\HTML::makeoption($dir, $dir, $value); } + $field = array( + 'type' => 'select', + 'value' => $_field + ); } else { // $field = $lng['panel']['dirsmissing']; // $field = ''; @@ -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; @@ -525,7 +523,7 @@ class FileDir */ public static function isFreeBSD($exact = false) { - if (($exact && PHP_OS == 'FreeBSD') || (! $exact && stristr(PHP_OS, 'BSD'))) { + if (($exact && PHP_OS == 'FreeBSD') || (!$exact && stristr(PHP_OS, 'BSD'))) { return true; } return false; diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index f2e37a79..0e6fab40 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -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'; diff --git a/lib/Froxlor/Settings/Store.php b/lib/Froxlor/Settings/Store.php index d19328f1..0b595aa3 100644 --- a/lib/Froxlor/Settings/Store.php +++ b/lib/Froxlor/Settings/Store.php @@ -1,4 +1,5 @@ 0) { $defaultips_new = explode(',', $newfieldvalue); - if (! empty($defaultips_old) && ! empty($newfieldvalue)) { + if (!empty($defaultips_old) && !empty($newfieldvalue)) { $in_value = $defaultips_old . ", " . $newfieldvalue; - } elseif (! empty($defaultips_old) && empty($newfieldvalue)) { + } elseif (!empty($defaultips_old) && empty($newfieldvalue)) { $in_value = $defaultips_old; } else { $in_value = $newfieldvalue; @@ -280,11 +281,11 @@ class Store if ($returnvalue !== false && is_array($fielddata) && isset($fielddata['settinggroup']) && $fielddata['settinggroup'] == 'system' && isset($fielddata['varname']) && $fielddata['varname'] == 'mysql_access_host') { $mysql_access_host_array = array_map('trim', explode(',', $newfieldvalue)); - if (in_array('127.0.0.1', $mysql_access_host_array) && ! in_array('localhost', $mysql_access_host_array)) { + if (in_array('127.0.0.1', $mysql_access_host_array) && !in_array('localhost', $mysql_access_host_array)) { $mysql_access_host_array[] = 'localhost'; } - if (! in_array('127.0.0.1', $mysql_access_host_array) && in_array('localhost', $mysql_access_host_array)) { + if (!in_array('127.0.0.1', $mysql_access_host_array) && in_array('localhost', $mysql_access_host_array)) { $mysql_access_host_array[] = '127.0.0.1'; } @@ -306,8 +307,8 @@ class Store private static function cleanMySQLAccessHost($value) { - if (substr($value, 0, 1) == '[' && substr($value, - 1) == ']') { - return substr($value, 1, - 1); + if (substr($value, 0, 1) == '[' && substr($value, -1) == ']') { + return substr($value, 1, -1); } return $value; } @@ -370,66 +371,85 @@ class Store } public static function storeSettingImage($fieldname, $fielddata) - { - if (isset($fielddata['settinggroup'], $fielddata['varname']) && is_array($fielddata) && $fielddata['settinggroup'] !== '' && $fielddata['varname'] !== '') { - $save_to = null; - $path = \Froxlor\Froxlor::getInstallDir().'/img/'; - $path = \Froxlor\FileDir::makeCorrectDir($path); + { + if (isset($fielddata['settinggroup'], $fielddata['varname']) && is_array($fielddata) && $fielddata['settinggroup'] !== '' && $fielddata['varname'] !== '') { + $save_to = null; + $path = \Froxlor\Froxlor::getInstallDir() . '/img/'; + $path = \Froxlor\FileDir::makeCorrectDir($path); - // New file? - if (isset($_FILES[$fieldname]) && $_FILES[$fieldname]['tmp_name']) { - // Make sure upload directory exists - if (!is_dir($path) && !mkdir($path, 0775)) { - throw new \Exception("img directory does not exist and cannot be created"); - } + // New file? + if (isset($_FILES[$fieldname]) && $_FILES[$fieldname]['tmp_name']) { + // Make sure upload directory exists + if (!is_dir($path) && !mkdir($path, 0775)) { + throw new \Exception("img directory does not exist and cannot be created"); + } - // Make sure we can write to the upload directory - if (!is_writable($path)) { - if (!chmod($path, 0775)) { - throw new \Exception("Cannot write to img directory"); - } - } + // Make sure we can write to the upload directory + if (!is_writable($path)) { + if (!chmod($path, 0775)) { + throw new \Exception("Cannot write to img directory"); + } + } - // 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"); - } + // Make sure mime-type matches an 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 - $spl = explode('.', $_FILES[$fieldname]['name']); - $file_extension = strtolower(array_pop($spl)); - unset($spl); + // Determine file extension + $spl = explode('.', $_FILES[$fieldname]['name']); + $file_extension = strtolower(array_pop($spl)); + unset($spl); - // 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"); - } + if (!in_array($file_extension, [ + 'jpeg', + 'jpg', + 'png', + 'gif' + ])) { + throw new Exception("Invalid file-extension, use one of: jpeg, jpg, png, gif"); + } - $save_to = 'img/'.$fielddata['image_name'].'.'.$file_extension.'?v='.time(); - } + // 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"); + } - // Delete file? - if ($fielddata['value'] !== "" && array_key_exists($fieldname.'_delete', $_POST) && $_POST[$fieldname.'_delete']) { - @unlink(\Froxlor\Froxlor::getInstallDir() . '/' . explode('?', $fielddata['value'], 2)[0]); - $save_to = ''; - } + $save_to = 'img/' . $fielddata['image_name'] . '.' . $file_extension . '?v=' . time(); + } - // Nothing changed - if ($save_to === null) { - return array( - $fielddata['settinggroup'] . '.' . $fielddata['varname'] => $fielddata['value'] - ); - } + // Delete file? + if ($fielddata['value'] !== "" && array_key_exists($fieldname . '_delete', $_POST) && $_POST[$fieldname . '_delete']) { + @unlink(\Froxlor\Froxlor::getInstallDir() . '/' . explode('?', $fielddata['value'], 2)[0]); + $save_to = ''; + } - if (Settings::Set($fielddata['settinggroup'] . '.' . $fielddata['varname'], $save_to) === false) { - return false; - } + // Nothing changed + if ($save_to === null) { + return array( + $fielddata['settinggroup'] . '.' . $fielddata['varname'] => $fielddata['value'] + ); + } - return array( - $fielddata['settinggroup'] . '.' . $fielddata['varname'] => $save_to - ); - } + if (Settings::Set($fielddata['settinggroup'] . '.' . $fielddata['varname'], $save_to) === false) { + return false; + } - return false; - } + return array( + $fielddata['settinggroup'] . '.' . $fielddata['varname'] => $save_to + ); + } + + return false; + } } diff --git a/lib/configfiles/bullseye.xml b/lib/configfiles/bullseye.xml index 45bcc26e..c24b3b45 100644 --- a/lib/configfiles/bullseye.xml +++ b/lib/configfiles/bullseye.xml @@ -3561,7 +3561,7 @@ postmaster_address = postmaster@ protocol lda { # Space separated list of plugins to load (default is global mail_plugins). - #mail_plugins = $mail_plugins + mail_plugins = $mail_plugins quota sieve } ]]> diff --git a/lib/configfiles/buster.xml b/lib/configfiles/buster.xml index 176e17b7..b976de04 100644 --- a/lib/configfiles/buster.xml +++ b/lib/configfiles/buster.xml @@ -3557,7 +3557,7 @@ postmaster_address = postmaster@ protocol lda { # Space separated list of plugins to load (default is global mail_plugins). - #mail_plugins = $mail_plugins + mail_plugins = $mail_plugins quota sieve } ]]> diff --git a/lib/init.php b/lib/init.php index 0448a244..83af9d66 100644 --- a/lib/init.php +++ b/lib/init.php @@ -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); diff --git a/lng/english.lng.php b/lng/english.lng.php index 60e2aeeb..7c73fef9 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -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
Default is /root/.acme.sh/acme.sh'; + +$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?'; diff --git a/lng/german.lng.php b/lng/german.lng.php index 5eefbdef..74d08e3f 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -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
Standard ist /root/.acme.sh/acme.sh'; + +$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?'; diff --git a/ssl_certificates.php b/ssl_certificates.php index cdc0b67d..4469e240 100644 --- a/ssl_certificates.php +++ b/ssl_certificates.php @@ -29,15 +29,23 @@ $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) { - try { - $json_result = Certificates::getLocal($userinfo, array( + if (isset($_POST['send']) && $_POST['send'] == 'send') { + try { + $json_result = Certificates::getLocal($userinfo, array( + 'id' => $id + ))->delete(); + $success_message = sprintf($lng['domains']['ssl_certificate_removed'], $id); + } 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 - ))->delete(); - $success_message = sprintf($lng['domains']['ssl_certificate_removed'], $id); - } catch (Exception $e) { - \Froxlor\UI\Response::dynamic_error($e->getMessage()); + ), $id); } } } diff --git a/templates/Sparkle/assets/css/main.css b/templates/Sparkle/assets/css/main.css index 8d6f7726..c571776c 100644 --- a/templates/Sparkle/assets/css/main.css +++ b/templates/Sparkle/assets/css/main.css @@ -82,6 +82,7 @@ header img { .login header img { margin: 0 auto; display: block; + max-width: calc(100% - 20px); } img.small { diff --git a/tests/Froxlor/ValidateTest.php b/tests/Froxlor/ValidateTest.php index d973154a..3d116ade 100644 --- a/tests/Froxlor/ValidateTest.php +++ b/tests/Froxlor/ValidateTest.php @@ -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); diff --git a/tests/Mysqls/MysqlsTest.php b/tests/Mysqls/MysqlsTest.php index 5673a474..da762ef1 100644 --- a/tests/Mysqls/MysqlsTest.php +++ b/tests/Mysqls/MysqlsTest.php @@ -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");