diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 00000000..26cec6c2 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,4 @@ +codecov: + notify: + require_ci_to_pass: no + diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..21c83ab0 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +custom: ['https://paypal.me/Froxlor'] diff --git a/.gitignore b/.gitignore index 8c981d1d..3d547882 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ install/update.log templates/* lib/userdata.inc.php +lib/userdata.inc.php.bak logs/* !logs/index.html .buildpath diff --git a/.travis.yml b/.travis.yml index b751d37c..4148f43a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,9 @@ language: php - +dist: bionic +services: + - docker php: -# - "5.4" -# - "5.6" -# - "7.0" - - "7.1" -# - "7.2" + - 7.3 branches: only: @@ -14,47 +12,56 @@ branches: matrix: include: - # - php: 5.6 - # env: deps=highest - # - php: 5.4 - # env: deps=lowest - - php: 7.1 - env: deps=highest - -mysql: - database: froxlor010 - username: root - encoding: utf8 + - php: 7.3 + env: "DOCKER_MYSQL_TYPE=mysql DOCKER_MYSQL_VERSION=5.6" + - php: 7.3 + env: "DOCKER_MYSQL_TYPE=mysql DOCKER_MYSQL_VERSION=5.7" + - php: 7.3 + env: "DOCKER_MYSQL_TYPE=mysql DOCKER_MYSQL_VERSION=8.0 STARTCMD='mysqld --default-authentication-plugin=mysql_native_password'" + - php: 7.3 + env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.3" + - php: 7.3 + env: "DOCKER_MYSQL_TYPE=mariadb DOCKER_MYSQL_VERSION=10.4" addons: apt: update: true -# build.xml includes that -#install: -# - composer install +before_install: + - export MYSQL_DATABASE=froxlor010 + - docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=fr0xl0r.TravisCI -e MYSQL_DATABASE=$MYSQL_DATABASE -p 3306:3306 $DOCKER_MYSQL_TYPE:$DOCKER_MYSQL_VERSION $STARTCMD + - sudo apt-get install -y ant + - > + export tries=0; + export max_tries=20; + while [[ true ]]; do + tries=$((tries + 1)); + echo "waiting for database server to start up... [$tries]"; + sleep 5; + # Now see that today's table is there, which would indicate that the cron job ran. + mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -s -e 'SHOW VARIABLES LIKE "%version%";' + look_exit=$?; + if [[ "$look_exit" = "0" ]]; then echo "Database server successfully started"; break; fi; + if [[ "$tries" -ge "$max_tries" ]]; then echo "Database server did not start in time"; exit 1; break; fi; + done; -service: - - mysql - -before_script: - - mysql -e 'CREATE DATABASE IF NOT EXISTS froxlor010' - - echo "USE mysql;\nUPDATE user SET password=PASSWORD('fr0xl0r.TravisCI') WHERE user='root';\nFLUSH PRIVILEGES;\n" | mysql -u root - - mysql -u root -pfr0xl0r.TravisCI froxlor010 < install/froxlor.sql - - mysql -u root -pfr0xl0r.TravisCI -e "CREATE USER 'froxlor010'@'localhost' IDENTIFIED BY 'fr0xl0r.TravisCI';" - - mysql -u root -pfr0xl0r.TravisCI -e "GRANT ALL ON froxlor010.* TO 'froxlor010'@'localhost';" +install: + - mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "CREATE DATABASE IF NOT EXISTS froxlor010;" + - mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "CREATE USER 'froxlor010'@'%' IDENTIFIED BY 'fr0xl0r.TravisCI';" + - mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "GRANT ALL ON froxlor010.* TO 'froxlor010'@'%';" + - mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI froxlor010 < install/froxlor.sql script: -# sufficient for travis - - ant phpunit-no-coverage -# - ant full-build-parallel -# -Dpdepend=$(pwd)/vendor/bin/pdepend -# -Dphpmd=$(pwd)/vendor/bin/phpmd -# -Dphpcpd=$(pwd)/vendor/bin/phpcpd -# -Dphpcs=$(pwd)/vendor/bin/phpcs -# -Dphploc=$(pwd)/vendor/bin/phploc -# -Dphpdox=$(pwd)/vendor/bin/phpdox -# -Dphpunit=$(pwd)/vendor/bin/phpunit + - ant phpunit + +after_success: + - bash <(curl -s https://codecov.io/bash) -f "build/logs/clover.xml" notifications: irc: "irc.freenode.org#froxlor" + webhooks: + urls: + - https://webhooks.gitter.im/e/bdf91d1c3f745e51f796 + on_success: always + on_failure: always + on_start: never diff --git a/README.md b/README.md index 6ae500ea..affecf3e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Build Status](https://travis-ci.com/Froxlor/Froxlor.svg?branch=master)](https://travis-ci.com/Froxlor/Froxlor) +[![Gitter](https://badges.gitter.im/Froxlor/community.svg)](https://gitter.im/Froxlor/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) # Froxlor @@ -53,7 +54,7 @@ https://files.froxlor.org/releases/froxlor-latest.tar.gz [MD5](https://files.fro [HowTo](https://github.com/Froxlor/Froxlor/wiki/Install-froxlor-on-debian) /etc/apt/sources.list.d/froxlor.list -> deb http://debian.froxlor.org {wheezy|jessie|stretch} main +> deb http://debian.froxlor.org {stretch|buster} main ### Gentoo repository diff --git a/actions/admin/settings/100.panel.php b/actions/admin/settings/100.panel.php index faf53644..ffbb9f4f 100644 --- a/actions/admin/settings/100.panel.php +++ b/actions/admin/settings/100.panel.php @@ -45,7 +45,7 @@ return array( 'settinggroup' => 'panel', 'varname' => 'default_theme', 'type' => 'option', - 'default' => 'Froxlor', + 'default' => 'Sparkle', 'option_mode' => 'one', 'option_options_method' => array( '\\Froxlor\\UI\\Template', diff --git a/actions/admin/settings/130.webserver.php b/actions/admin/settings/130.webserver.php index 66d41047..e5b550a7 100644 --- a/actions/admin/settings/130.webserver.php +++ b/actions/admin/settings/130.webserver.php @@ -250,6 +250,23 @@ return array( 'default' => '', 'save_method' => 'storeSettingField' ), + 'system_default_sslvhostconf' => array( + 'label' => $lng['serversettings']['default_sslvhostconf'], + 'settinggroup' => 'system', + 'varname' => 'default_sslvhostconf', + 'type' => 'text', + 'default' => '', + 'save_method' => 'storeSettingField', + 'visible' => \Froxlor\Settings::Get('system.use_ssl') == 1 + ), + 'system_include_default_vhostconf' => array( + 'label' => $lng['serversettings']['includedefault_sslvhostconf'], + 'settinggroup' => 'system', + 'varname' => 'include_default_vhostconf', + 'type' => 'bool', + 'default' => false, + 'save_method' => 'storeSettingField' + ), 'system_apache_globaldiropt' => array( 'label' => $lng['serversettings']['apache_globaldiropt'], 'settinggroup' => 'system', diff --git a/actions/admin/settings/131.ssl.php b/actions/admin/settings/131.ssl.php index 6717e1b8..b292dc0a 100644 --- a/actions/admin/settings/131.ssl.php +++ b/actions/admin/settings/131.ssl.php @@ -54,6 +54,16 @@ return array( 'default' => 'ECDH+AESGCM:ECDH+AES256:!aNULL:!MD5:!DSS:!DH:!AES128', 'save_method' => 'storeSettingField' ), + 'system_tlsv13_cipher_list' => array( + 'label' => $lng['serversettings']['ssl']['tlsv13_cipher_list'], + 'settinggroup' => 'system', + 'varname' => 'tlsv13_cipher_list', + 'type' => 'string', + 'string_emptyallowed' => true, + 'default' => '', + 'visible' => \Froxlor\Settings::Get('system.webserver') == "apache2" && \Froxlor\Settings::Get('system.apache24') == 1, + 'save_method' => 'storeSettingField', + ), 'system_ssl_cert_file' => array( 'label' => $lng['serversettings']['ssl']['ssl_cert_file'], 'settinggroup' => 'system', @@ -128,10 +138,9 @@ return array( 'settinggroup' => 'system', 'varname' => 'leapiversion', 'type' => 'option', - 'default' => '1', + 'default' => '2', 'option_mode' => 'one', 'option_options' => array( - '1' => 'ACME v1', '2' => 'ACME v2' ), 'save_method' => 'storeSettingField' diff --git a/actions/admin/settings/136.phpfpm.php b/actions/admin/settings/136.phpfpm.php index db1839ce..eca70ba4 100644 --- a/actions/admin/settings/136.phpfpm.php +++ b/actions/admin/settings/136.phpfpm.php @@ -99,7 +99,7 @@ return array( 'settinggroup' => 'phpfpm', 'varname' => 'use_mod_proxy', 'type' => 'bool', - 'default' => false, + 'default' => true, 'visible' => \Froxlor\Settings::Get('system.apache24'), 'save_method' => 'storeSettingField' ), diff --git a/actions/admin/settings/160.nameserver.php b/actions/admin/settings/160.nameserver.php index a7df3322..67260bfa 100644 --- a/actions/admin/settings/160.nameserver.php +++ b/actions/admin/settings/160.nameserver.php @@ -107,6 +107,22 @@ return array( 'default' => false, 'save_method' => 'storeSettingField' ), + 'system_dns_createcaaentry' => array( + 'label' => $lng['serversettings']['caa_entry'], + 'settinggroup' => 'system', + 'varname' => 'dns_createcaaentry', + 'type' => 'bool', + 'default' => true, + 'save_method' => 'storeSettingField' + ), + 'caa_caa_entry' => array( + 'label' => $lng['serversettings']['caa_entry_custom'], + 'settinggroup' => 'caa', + 'varname' => 'caa_entry', + 'type' => 'text', + 'default' => '', + 'save_method' => 'storeSettingField' + ), 'system_defaultttl' => array( 'label' => $lng['serversettings']['defaultttl'], 'settinggroup' => 'system', diff --git a/admin_autoupdate.php b/admin_autoupdate.php index 8598a5b0..8ef41962 100644 --- a/admin_autoupdate.php +++ b/admin_autoupdate.php @@ -36,6 +36,15 @@ if (! extension_loaded('zip')) { )); } +// 0.10.x requires 7.0 at least +if (version_compare("7.0.0", PHP_VERSION, ">=")) { + \Froxlor\UI\Response::redirectTo($filename, array( + 's' => $s, + 'page' => 'error', + 'errno' => 10 + )); +} + // display initial version check if ($page == 'overview') { @@ -43,8 +52,11 @@ if ($page == 'overview') { $log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "checking auto-update"); // check for new version - $latestversion = HttpClient::urlGet(UPDATE_URI); - + try { + $latestversion = HttpClient::urlGet(UPDATE_URI, true, 3); + } catch (\Exception $e) { + \Froxlor\UI\Response::dynamic_error("Version-check currently unavailable, please try again later"); + } $latestversion = explode('|', $latestversion); if (is_array($latestversion) && count($latestversion) >= 1) { @@ -175,6 +187,8 @@ elseif ($page == 'extract') { $zip->close(); // success - remove unused archive @unlink($localArchive); + // wait a bit before we redirect to be sure + sleep(2); } else { // error \Froxlor\UI\Response::redirectTo($filename, array( @@ -216,5 +230,6 @@ elseif ($page == 'error') { // 7 = local archive does not exist // 8 = could not extract archive // 9 = checksum mismatch + // 10 = $row['customerid'] )); - $row['webspace_used'] = round($usages['webspace'] / 1024, $dec_places); - $row['mailspace_used'] = round($usages['mail'] / 1024, $dec_places); - $row['dbspace_used'] = round($usages['mysql'] / 1024, $dec_places); - + if ($usages) + { + $row['webspace_used'] = round($usages['webspace'] / 1024, $dec_places); + $row['mailspace_used'] = round($usages['mail'] / 1024, $dec_places); + $row['dbspace_used'] = round($usages['mysql'] / 1024, $dec_places); + } else { + $row['webspace_used'] = 0; + $row['mailspace_used'] = 0; + $row['dbspace_used'] = 0; + } $row['traffic_used'] = round($row['traffic_used'] / (1024 * 1024), $dec_places); $row['traffic'] = round($row['traffic'] / (1024 * 1024), $dec_places); $row['diskspace_used'] = round($row['diskspace_used'] / 1024, $dec_places); diff --git a/admin_index.php b/admin_index.php index 25e3fba0..3415d14f 100644 --- a/admin_index.php +++ b/admin_index.php @@ -387,8 +387,6 @@ if ($page == 'overview') { } } elseif ($page == 'apikeys' && Settings::Get('api.enabled') == 1) { require_once __DIR__ . '/api_keys.php'; -} elseif ($page == 'apihelp' && Settings::Get('api.enabled') == 1) { - require_once __DIR__ . '/apihelp.php'; } elseif ($page == '2fa' && Settings::Get('2fa.enabled') == 1) { require_once __DIR__ . '/2fa.php'; } diff --git a/admin_logger.php b/admin_logger.php index 34b519e1..3d317533 100644 --- a/admin_logger.php +++ b/admin_logger.php @@ -83,7 +83,7 @@ if ($page == 'log' && $userinfo['change_serversettings'] == '1') { case \Froxlor\FroxlorLogger::LOGIN_ACTION: $_action = $lng['logger']['login']; break; - case LOG_ERROR: + case \Froxlor\FroxlorLogger::LOG_ERROR: $_action = $lng['logger']['intern']; break; default: diff --git a/admin_plans.php b/admin_plans.php index cae7fb93..bf30d5ba 100644 --- a/admin_plans.php +++ b/admin_plans.php @@ -17,6 +17,7 @@ define('AREA', 'admin'); require './lib/init.php'; +use Froxlor\Api\Commands\HostingPlans; use Froxlor\Database\Database; use Froxlor\Settings; @@ -69,22 +70,26 @@ if ($page == '' || $page == 'overview') { eval("echo \"" . \Froxlor\UI\Template::getTemplate("plans/plans") . "\";"); } elseif ($action == 'delete' && $id != 0) { - $result_stmt = Database::prepare(" - SELECT * FROM `" . TABLE_PANEL_PLANS . "` WHERE `id` = :id"); - $result = Database::pexecute_first($result_stmt, array( - 'id' => $id - )); + try { + $json_result = HostingPlans::getLocal($userinfo, array( + 'id' => $id + ))->get(); + } catch (Exception $e) { + \Froxlor\UI\Response::dynamic_error($e->getMessage()); + } + $result = json_decode($json_result, true)['data']; if ($result['id'] != 0 && $result['id'] == $id && (int) $userinfo['adminid'] == $result['adminid']) { if (isset($_POST['send']) && $_POST['send'] == 'send') { - $del_stmt = Database::prepare(" - DELETE FROM `" . TABLE_PANEL_PLANS . "` WHERE `id` = :id"); - Database::pexecute($del_stmt, array( - 'id' => $id - )); + try { + HostingPlans::getLocal($userinfo, array( + 'id' => $id + ))->delete(); + } catch (Exception $e) { + \Froxlor\UI\Response::dynamic_error($e->getMessage()); + } - $log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "Plan '" . $result['name'] . "' has been deleted by '" . $userinfo['loginname'] . "'"); \Froxlor\UI\Response::redirectTo($filename, array( 'page' => $page, 's' => $s @@ -102,113 +107,11 @@ if ($page == '' || $page == 'overview') { } elseif ($action == 'add') { if (isset($_POST['send']) && $_POST['send'] == 'send') { - $name = \Froxlor\Validate\Validate::validate($_POST['name'], 'name'); - $description = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $_POST['description']), 'description', '/^[^\0]*$/'); - - $value_arr = array(); - - if (empty($name)) { - \Froxlor\UI\Response::standard_error('stringmustntbeempty', 'name'); + try { + HostingPlans::getLocal($userinfo, $_POST)->add(); + } catch (Exception $e) { + \Froxlor\UI\Response::dynamic_error($e->getMessage()); } - - $value_arr['diskspace'] = (int)($_POST['diskspace']); - if (isset($_POST['diskspace_ul'])) { - $value_arr['diskspace'] = - 1; - } - - $value_arr['traffic'] = $_POST['traffic']; - if (isset($_POST['traffic_ul'])) { - $value_arr['traffic'] = - 1; - } - - $value_arr['subdomains'] = (int)($_POST['subdomains']); - if (isset($_POST['subdomains_ul'])) { - $value_arr['subdomains'] = - 1; - } - - $value_arr['emails'] = (int)($_POST['emails']); - if (isset($_POST['emails_ul'])) { - $value_arr['emails'] = - 1; - } - - $value_arr['email_accounts'] = (int)($_POST['email_accounts']); - if (isset($_POST['email_accounts_ul'])) { - $value_arr['email_accounts'] = - 1; - } - - $value_arr['email_forwarders'] = (int)($_POST['email_forwarders']); - if (isset($_POST['email_forwarders_ul'])) { - $value_arr['email_forwarders'] = - 1; - } - - if (Settings::Get('system.mail_quota_enabled') == '1') { - $value_arr['email_quota'] = \Froxlor\Validate\Validate::validate($_POST['email_quota'], 'email_quota', '/^\d+$/', 'vmailquotawrong', array( - '0', - '' - )); - if (isset($_POST['email_quota_ul'])) { - $value_arr['email_quota'] = - 1; - } - } else { - $value_arr['email_quota'] = - 1; - } - - $value_arr['email_imap'] = 0; - if (isset($_POST['email_imap'])) { - $value_arr['email_imap'] = (int)($_POST['email_imap']); - } - - $value_arr['email_pop3'] = 0; - if (isset($_POST['email_pop3'])) { - $value_arr['email_pop3'] = (int)($_POST['email_pop3']); - } - - $value_arr['ftps'] = (int)($_POST['ftps']); - if (isset($_POST['ftps_ul'])) { - $value_arr['ftps'] = - 1; - } - - $value_arr['mysqls'] = (int)($_POST['mysqls']); - if (isset($_POST['mysqls_ul'])) { - $value_arr['mysqls'] = - 1; - } - - $value_arr['phpenabled'] = 0; - if (isset($_POST['phpenabled'])) { - $value_arr['phpenabled'] = intval($_POST['phpenabled']); - } - - $value_arr['allowed_phpconfigs'] = array(); - if (isset($_POST['allowed_phpconfigs']) && is_array($_POST['allowed_phpconfigs'])) { - foreach ($_POST['allowed_phpconfigs'] as $allowed_phpconfig) { - $allowed_phpconfig = intval($allowed_phpconfig); - $value_arr['allowed_phpconfigs'][] = $allowed_phpconfig; - } - } - - $value_arr['perlenabled'] = 0; - if (isset($_POST['perlenabled'])) { - $value_arr['perlenabled'] = intval($_POST['perlenabled']); - } - - $value_arr['dnsenabled'] = 0; - if (isset($_POST['dnsenabled'])) { - $value_arr['dnsenabled'] = intval($_POST['dnsenabled']); - } - - $ins_stmt = Database::prepare(" - INSERT INTO `" . TABLE_PANEL_PLANS . "` - SET `adminid` = :adminid, `name` = :name, `description` = :desc, `value` = :valuearr, `ts` = UNIX_TIMESTAMP(); - "); - $ins_data = array( - 'adminid' => $userinfo['adminid'], - 'name' => $name, - 'desc' => $description, - 'valuearr' => json_encode($value_arr) - ); - Database::pexecute($ins_stmt, $ins_data); - - $log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "added plan '" . $name . "'"); \Froxlor\UI\Response::redirectTo($filename, array( 'page' => $page, 's' => $s @@ -266,11 +169,14 @@ if ($page == '' || $page == 'overview') { eval("echo \"" . \Froxlor\UI\Template::getTemplate("plans/plans_add") . "\";"); } } elseif ($action == 'edit' && $id != 0) { - $result_stmt = Database::prepare(" - SELECT * FROM `" . TABLE_PANEL_PLANS . "` WHERE `id` = :id"); - $result = Database::pexecute_first($result_stmt, array( - 'id' => $id - )); + try { + $json_result = HostingPlans::getLocal($userinfo, array( + 'id' => $id + ))->get(); + } catch (Exception $e) { + \Froxlor\UI\Response::dynamic_error($e->getMessage()); + } + $result = json_decode($json_result, true)['data']; if ($result['name'] != '') { @@ -284,110 +190,13 @@ if ($page == '' || $page == 'overview') { if (isset($_POST['send']) && $_POST['send'] == 'send') { - $name = \Froxlor\Validate\Validate::validate($_POST['name'], 'name'); - $description = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $_POST['description']), 'description', '/^[^\0]*$/'); - - $value_arr = array(); - - $value_arr['diskspace'] = (int)($_POST['diskspace']); - if (isset($_POST['diskspace_ul'])) { - $value_arr['diskspace'] = - 1; + try { + HostingPlans::getLocal($userinfo, array( + 'id' => $id + ))->update(); + } catch (Exception $e) { + \Froxlor\UI\Response::dynamic_error($e->getMessage()); } - - $value_arr['traffic'] = $_POST['traffic']; - if (isset($_POST['traffic_ul'])) { - $value_arr['traffic'] = - 1; - } - - $value_arr['subdomains'] = (int)($_POST['subdomains']); - if (isset($_POST['subdomains_ul'])) { - $value_arr['subdomains'] = - 1; - } - - $value_arr['emails'] = (int)($_POST['emails']); - if (isset($_POST['emails_ul'])) { - $value_arr['emails'] = - 1; - } - - $value_arr['email_accounts'] = (int)($_POST['email_accounts']); - if (isset($_POST['email_accounts_ul'])) { - $value_arr['email_accounts'] = - 1; - } - - $value_arr['email_forwarders'] = (int)($_POST['email_forwarders']); - if (isset($_POST['email_forwarders_ul'])) { - $value_arr['email_forwarders'] = - 1; - } - - if (Settings::Get('system.mail_quota_enabled') == '1') { - $value_arr['email_quota'] = \Froxlor\Validate\Validate::validate($_POST['email_quota'], 'email_quota', '/^\d+$/', 'vmailquotawrong', array( - '0', - '' - )); - if (isset($_POST['email_quota_ul'])) { - $value_arr['email_quota'] = - 1; - } - } else { - $value_arr['email_quota'] = - 1; - } - - $value_arr['email_imap'] = 0; - if (isset($_POST['email_imap'])) { - $value_arr['email_imap'] = (int)($_POST['email_imap']); - } - - $value_arr['email_pop3'] = 0; - if (isset($_POST['email_pop3'])) { - $value_arr['email_pop3'] = (int)($_POST['email_pop3']); - } - - $value_arr['ftps'] = (int)($_POST['ftps']); - if (isset($_POST['ftps_ul'])) { - $value_arr['ftps'] = - 1; - } - - $value_arr['mysqls'] = (int)($_POST['mysqls']); - if (isset($_POST['mysqls_ul'])) { - $value_arr['mysqls'] = - 1; - } - - $value_arr['phpenabled'] = 0; - if (isset($_POST['phpenabled'])) { - $value_arr['phpenabled'] = intval($_POST['phpenabled']); - } - - $value_arr['allowed_phpconfigs'] = array(); - if (isset($_POST['allowed_phpconfigs']) && is_array($_POST['allowed_phpconfigs'])) { - foreach ($_POST['allowed_phpconfigs'] as $allowed_phpconfig) { - $allowed_phpconfig = intval($allowed_phpconfig); - $value_arr['allowed_phpconfigs'][] = $allowed_phpconfig; - } - } - - $value_arr['perlenabled'] = 0; - if (isset($_POST['perlenabled'])) { - $value_arr['perlenabled'] = intval($_POST['perlenabled']); - } - - $value_arr['dnsenabled'] = 0; - if (isset($_POST['dnsenabled'])) { - $value_arr['dnsenabled'] = intval($_POST['dnsenabled']); - } - - $ins_stmt = Database::prepare(" - UPDATE `" . TABLE_PANEL_PLANS . "` - SET `name` = :name, `description` = :desc, `value` = :valuearr, `ts` = UNIX_TIMESTAMP() - WHERE `id` = :id - "); - $ins_data = array( - 'name' => $name, - 'desc' => $description, - 'valuearr' => json_encode($value_arr), - 'id' => $id - ); - Database::pexecute($ins_stmt, $ins_data); - - $log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "updated plan '" . $name . "'"); \Froxlor\UI\Response::redirectTo($filename, array( 'page' => $page, 's' => $s @@ -502,11 +311,14 @@ if ($page == '' || $page == 'overview') { } } elseif ($action == 'jqGetPlanValues') { $planid = isset($_POST['planid']) ? (int) $_POST['planid'] : 0; - $result_stmt = Database::prepare(" - SELECT * FROM `" . TABLE_PANEL_PLANS . "` WHERE `id` = :id"); - $result = Database::pexecute_first($result_stmt, array( - 'id' => $planid - )); + try { + $json_result = HostingPlans::getLocal($userinfo, array( + 'id' => $planid + ))->get(); + } catch (Exception $e) { + \Froxlor\UI\Response::dynamic_error($e->getMessage()); + } + $result = json_decode($json_result, true)['data']; echo $result['value']; exit(); } diff --git a/api_keys.php b/api_keys.php index fec078e7..0c3126e5 100644 --- a/api_keys.php +++ b/api_keys.php @@ -88,15 +88,17 @@ if ($action == 'delete') { $valid_until = isset($_POST['valid_until']) ? (int) $_POST['valid_until'] : - 1; // validate allowed_from - $ip_list = array_map('trim', explode(",", $allowed_from)); - $_check_list = $ip_list; - foreach ($_check_list as $idx => $ip) { - if (\Froxlor\Validate\Validate::validate_ip2($ip, true, 'invalidip', true, true) == false) { - unset($ip_list[$idx]); + if (! empty($allowed_from)) { + $ip_list = array_map('trim', explode(",", $allowed_from)); + $_check_list = $ip_list; + foreach ($_check_list as $idx => $ip) { + if (\Froxlor\Validate\Validate::validate_ip2($ip, true, 'invalidip', true, true) == false) { + unset($ip_list[$idx]); + } } + $ip_list = array_map('inet_ntop', array_map('inet_pton', $ip_list)); + $allowed_from = implode(",", array_unique($ip_list)); } - $ip_list = array_map('inet_ntop', array_map('inet_pton', $ip_list)); - $allowed_from = implode(",", array_unique($ip_list)); if ($valid_until <= 0 || ! is_numeric($valid_until)) { $valid_until = - 1; diff --git a/build.xml b/build.xml index 291013db..e489f847 100644 --- a/build.xml +++ b/build.xml @@ -226,14 +226,29 @@ - + + + + + + + + + + + - + + diff --git a/composer.json b/composer.json index 4299118e..9312338c 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "docs": "https://github.com/Froxlor/Froxlor/wiki" }, "require": { - "php": ">=5.6", + "php": ">=7.0", "ext-session": "*", "ext-ctype": "*", "ext-pdo": "*", @@ -49,17 +49,16 @@ "algo26-matthias/idna-convert": "^2.1" }, "require-dev": { - "phpunit/phpunit": "6.5.13", - "pdepend/pdepend": "2.5.0", - "phpmd/phpmd": "2.6.0", - "sebastian/phpcpd": "3.0.1", - "squizlabs/php_codesniffer": "3.3.2", - "phploc/phploc": "3.0.1", - "theseer/phpdox": "0.11.2", - "phpunit/php-invoker": "1.1.4", - "php": ">=7.1", + "phpunit/phpunit": "^8", + "php": ">=7.3", "ext-pcntl": "*", - "phpcompatibility/php-compatibility": "*" + "phpcompatibility/php-compatibility": "*", + "squizlabs/php_codesniffer": "*", + "pdepend/pdepend": "^2.5", + "sebastian/phpcpd": "^4.1", + "theseer/phpdox": "^0.12.0", + "phploc/phploc": "^5.0", + "phpmd/phpmd": "^2.6" }, "suggest": { "ext-bcmath": "*", diff --git a/composer.lock b/composer.lock index bbfe2827..f8c7a813 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5a09e82c87504e904337a4fc8a80e3a8", + "content-hash": "77819131afd1abe70f1ea6caad9fc3e5", "packages": [ { "name": "algo26-matthias/idna-convert", @@ -56,16 +56,16 @@ }, { "name": "monolog/monolog", - "version": "1.24.0", + "version": "1.25.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" + "reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/70e65a5470a42cfec1a7da00d30edb6e617e8dcf", + "reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf", "shasum": "" }, "require": { @@ -130,20 +130,20 @@ "logging", "psr-3" ], - "time": "2018-11-05T09:00:11+00:00" + "time": "2019-09-06T13:49:17+00:00" }, { "name": "phpmailer/phpmailer", - "version": "v6.0.7", + "version": "v6.1.1", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "0c41a36d4508d470e376498c1c0c527aa36a2d59" + "reference": "26bd96350b0b2fcbf0ef4e6f0f9cf3528302a9d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/0c41a36d4508d470e376498c1c0c527aa36a2d59", - "reference": "0c41a36d4508d470e376498c1c0c527aa36a2d59", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/26bd96350b0b2fcbf0ef4e6f0f9cf3528302a9d8", + "reference": "26bd96350b0b2fcbf0ef4e6f0f9cf3528302a9d8", "shasum": "" }, "require": { @@ -176,17 +176,17 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-2.1" + "LGPL-2.1-only" ], "authors": [ - { - "name": "Jim Jagielski", - "email": "jimjag@gmail.com" - }, { "name": "Marcus Bointon", "email": "phpmailer@synchromedia.co.uk" }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, { "name": "Andy Prevost", "email": "codeworxtech@users.sourceforge.net" @@ -196,7 +196,7 @@ } ], "description": "PHPMailer is a full-featured email creation and transfer class for PHP", - "time": "2019-02-01T15:04:28+00:00" + "time": "2019-09-27T21:33:43+00:00" }, { "name": "psr/log", @@ -247,16 +247,16 @@ }, { "name": "robthree/twofactorauth", - "version": "1.6.5", + "version": "1.6.7", "source": { "type": "git", "url": "https://github.com/RobThree/TwoFactorAuth.git", - "reference": "f5f58a4c62d0336a0e6175856894a51f3565dad2" + "reference": "3407c33775391fa8c36f7d766f26c5e59a736374" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/f5f58a4c62d0336a0e6175856894a51f3565dad2", - "reference": "f5f58a4c62d0336a0e6175856894a51f3565dad2", + "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/3407c33775391fa8c36f7d766f26c5e59a736374", + "reference": "3407c33775391fa8c36f7d766f26c5e59a736374", "shasum": "" }, "require": { @@ -294,33 +294,35 @@ "php", "tfa" ], - "time": "2018-06-09T10:09:59+00:00" + "time": "2019-06-21T08:51:04+00:00" } ], "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + "reference": "a2c590166b2133a4633738648b6b064edae0814a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", + "reference": "a2c590166b2133a4633738648b6b064edae0814a", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { - "athletic/athletic": "~0.1.8", + "doctrine/coding-standard": "^6.0", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { @@ -345,25 +347,25 @@ } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], - "time": "2017-07-22T11:58:36+00:00" + "time": "2019-03-17T17:37:11+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.8.1", + "version": "1.9.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", "shasum": "" }, "require": { @@ -398,28 +400,28 @@ "object", "object graph" ], - "time": "2018-06-11T23:09:50+00:00" + "time": "2019-08-09T12:45:53+00:00" }, { "name": "nikic/php-parser", - "version": "v3.1.5", + "version": "v4.2.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce" + "reference": "97e59c7a16464196a8b9c77c47df68e4a39a45c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", - "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/97e59c7a16464196a8b9c77c47df68e4a39a45c4", + "reference": "97e59c7a16464196a8b9c77c47df68e4a39a45c4", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=5.5" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" }, "bin": [ "bin/php-parse" @@ -427,7 +429,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -449,30 +451,30 @@ "parser", "php" ], - "time": "2018-02-28T20:30:58+00:00" + "time": "2019-09-01T07:51:21+00:00" }, { "name": "pdepend/pdepend", - "version": "2.5.0", + "version": "2.5.2", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "0c50874333149c0dad5a2877801aed148f2767ff" + "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/0c50874333149c0dad5a2877801aed148f2767ff", - "reference": "0c50874333149c0dad5a2877801aed148f2767ff", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/9daf26d0368d4a12bed1cacae1a9f3a6f0adf239", + "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239", "shasum": "" }, "require": { "php": ">=5.3.7", - "symfony/config": "^2.3.0|^3", - "symfony/dependency-injection": "^2.3.0|^3", - "symfony/filesystem": "^2.3.0|^3" + "symfony/config": "^2.3.0|^3|^4", + "symfony/dependency-injection": "^2.3.0|^3|^4", + "symfony/filesystem": "^2.3.0|^3|^4" }, "require-dev": { - "phpunit/phpunit": "^4.4.0,<4.8", + "phpunit/phpunit": "^4.8|^5.7", "squizlabs/php_codesniffer": "^2.0.0" }, "bin": [ @@ -489,26 +491,26 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2017-01-19T14:23:36+00:00" + "time": "2017-12-13T13:21:38+00:00" }, { "name": "phar-io/manifest", - "version": "1.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^1.0.1", + "phar-io/version": "^2.0", "php": "^5.6 || ^7.0" }, "type": "library", @@ -544,20 +546,20 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "1.0.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { @@ -591,20 +593,20 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { "name": "phpcompatibility/php-compatibility", - "version": "9.1.1", + "version": "9.3.1", "source": { "type": "git", "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "2b63c5d284ab8857f7b1d5c240ddb507a6b2293c" + "reference": "9999344e47e7af6b00e1a898eacc4e4368fb7196" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/2b63c5d284ab8857f7b1d5c240ddb507a6b2293c", - "reference": "2b63c5d284ab8857f7b1d5c240ddb507a6b2293c", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9999344e47e7af6b00e1a898eacc4e4368fb7196", + "reference": "9999344e47e7af6b00e1a898eacc4e4368fb7196", "shasum": "" }, "require": { @@ -618,7 +620,7 @@ "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" }, "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", + "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." }, "type": "phpcodesniffer-standard", @@ -627,10 +629,6 @@ "LGPL-3.0-or-later" ], "authors": [ - { - "name": "Contributors", - "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" - }, { "name": "Wim Godden", "homepage": "https://github.com/wimg", @@ -640,6 +638,10 @@ "name": "Juliette Reinders Folmer", "homepage": "https://github.com/jrfnl", "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" } ], "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", @@ -649,39 +651,37 @@ "phpcs", "standards" ], - "time": "2018-12-30T23:16:27+00:00" + "time": "2019-09-05T18:36:49+00:00" }, { "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { - "php": ">=5.5" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "~6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -703,30 +703,30 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "version": "4.3.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", + "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", "shasum": "" }, "require": { "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", + "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", + "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", "webmozart/assert": "^1.0" }, "require-dev": { - "doctrine/instantiator": "~1.0.5", + "doctrine/instantiator": "^1.0.5", "mockery/mockery": "^1.0", "phpunit/phpunit": "^6.4" }, @@ -754,41 +754,40 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "time": "2019-09-12T14:27:41+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.4.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "phpdocumentor/reflection-common": "^1.0" + "php": "^7.1", + "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -801,31 +800,28 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14T14:27:02+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2019-08-22T18:11:29+00:00" }, { "name": "phploc/phploc", - "version": "3.0.1", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phploc.git", - "reference": "74f917e6f80f291856989960d31afa44a4196859" + "reference": "5b714ccb7cb8ca29ccf9caf6eb1aed0131d3a884" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phploc/zipball/74f917e6f80f291856989960d31afa44a4196859", - "reference": "74f917e6f80f291856989960d31afa44a4196859", + "url": "https://api.github.com/repos/sebastianbergmann/phploc/zipball/5b714ccb7cb8ca29ccf9caf6eb1aed0131d3a884", + "reference": "5b714ccb7cb8ca29ccf9caf6eb1aed0131d3a884", "shasum": "" }, "require": { - "php": ">=5.6", - "sebastian/finder-facade": "~1.1", - "sebastian/git": "~2.1", - "sebastian/version": "~1.0.3|~2.0", - "symfony/console": "~2.5|~3.0" - }, - "require-dev": { - "phpunit/phpunit": "~5" + "php": "^7.2", + "sebastian/finder-facade": "^1.1", + "sebastian/version": "^2.0", + "symfony/console": "^4.0" }, "bin": [ "phploc" @@ -833,7 +829,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -854,20 +850,20 @@ ], "description": "A tool for quickly measuring the size of a PHP project.", "homepage": "https://github.com/sebastianbergmann/phploc", - "time": "2016-04-25T08:11:21+00:00" + "time": "2019-03-16T10:41:19+00:00" }, { "name": "phpmd/phpmd", - "version": "2.6.0", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374" + "reference": "a05a999c644f4bc9a204846017db7bb7809fbe4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/4e9924b2c157a3eb64395460fcf56b31badc8374", - "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/a05a999c644f4bc9a204846017db7bb7809fbe4c", + "reference": "a05a999c644f4bc9a204846017db7bb7809fbe4c", "shasum": "" }, "require": { @@ -876,13 +872,15 @@ "php": ">=5.3.9" }, "require-dev": { - "phpunit/phpunit": "^4.0", + "gregwar/rst": "^1.0", + "mikey179/vfsstream": "^1.6.4", + "phpunit/phpunit": "^4.8.36 || ^5.7.27", "squizlabs/php_codesniffer": "^2.0" }, "bin": [ "src/bin/phpmd" ], - "type": "project", + "type": "library", "autoload": { "psr-0": { "PHPMD\\": "src/main/php" @@ -899,20 +897,20 @@ "homepage": "https://github.com/manuelpichler", "role": "Project Founder" }, - { - "name": "Other contributors", - "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", - "role": "Contributors" - }, { "name": "Marc Würth", "email": "ravage@bluewin.ch", "homepage": "https://github.com/ravage84", "role": "Project Maintainer" + }, + { + "name": "Other contributors", + "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", + "role": "Contributors" } ], "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", - "homepage": "http://phpmd.org/", + "homepage": "https://phpmd.org/", "keywords": [ "mess detection", "mess detector", @@ -920,26 +918,26 @@ "phpmd", "pmd" ], - "time": "2017-01-20T14:41:10+00:00" + "time": "2019-07-30T21:13:32+00:00" }, { "name": "phpspec/prophecy", - "version": "1.8.0", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", + "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", "sebastian/comparator": "^1.1|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, @@ -954,8 +952,8 @@ } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -983,44 +981,44 @@ "spy", "stub" ], - "time": "2018-08-05T17:53:17+00:00" + "time": "2019-10-03T11:07:50+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.3.2", + "version": "7.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac" + "reference": "aa0d179a13284c7420fc281fc32750e6cc7c9e2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa0d179a13284c7420fc281fc32750e6cc7c9e2f", + "reference": "aa0d179a13284c7420fc281fc32750e6cc7c9e2f", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.0", - "phpunit/php-file-iterator": "^1.4.2", + "php": "^7.2", + "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", + "phpunit/php-token-stream": "^3.1.1", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", + "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^8.2.2" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -1046,29 +1044,32 @@ "testing", "xunit" ], - "time": "2018-04-06T15:36:58+00:00" + "time": "2019-09-17T06:24:36+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.5", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "050bedf145a257b1ff02746c31894800e5122946" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", + "reference": "050bedf145a257b1ff02746c31894800e5122946", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -1080,53 +1081,6 @@ "license": [ "BSD-3-Clause" ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2017-11-27T13:52:08+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "1.1.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "86074bf0fc2caf02ec8819a93f65a37cd0b44c8e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/86074bf0fc2caf02ec8819a93f65a37cd0b44c8e", - "reference": "86074bf0fc2caf02ec8819a93f65a37cd0b44c8e", - "shasum": "" - }, - "require": { - "ext-pcntl": "*", - "php": ">=5.3.3", - "phpunit/php-timer": ">=1.0.6" - }, - "require-dev": { - "phpunit/phpunit": "~4" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], "authors": [ { "name": "Sebastian Bergmann", @@ -1134,12 +1088,13 @@ "role": "lead" } ], - "description": "Utility class for invoking callables with a timeout.", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", "keywords": [ - "process" + "filesystem", + "iterator" ], - "time": "2015-06-21T13:32:55+00:00" + "time": "2018-09-13T20:33:42+00:00" }, { "name": "phpunit/php-text-template", @@ -1184,28 +1139,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -1220,7 +1175,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1229,33 +1184,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.2", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -1278,57 +1233,56 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27T05:48:46+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "6.5.13", + "version": "8.4.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "0973426fb012359b2f18d3bd1e90ef1172839693" + "reference": "366a4a0f2b971fd43b7c351d621e8dd7d7131869" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0973426fb012359b2f18d3bd1e90ef1172839693", - "reference": "0973426fb012359b2f18d3bd1e90ef1172839693", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/366a4a0f2b971fd43b7c351d621e8dd7d7131869", + "reference": "366a4a0f2b971fd43b7c351d621e8dd7d7131869", "shasum": "" }, "require": { + "doctrine/instantiator": "^1.2.0", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", - "php": "^7.0", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", - "phpunit/php-file-iterator": "^1.4.3", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.9.1", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.2", + "phpspec/prophecy": "^1.8.1", + "phpunit/php-code-coverage": "^7.0.7", + "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.9", - "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", - "sebastian/environment": "^3.1", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.2", + "sebastian/exporter": "^3.1.1", + "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", "sebastian/version": "^2.0.1" }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" - }, "require-dev": { "ext-pdo": "*" }, "suggest": { + "ext-soap": "*", "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" @@ -1336,7 +1290,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5.x-dev" + "dev-master": "8.4-dev" } }, "autoload": { @@ -1362,67 +1316,7 @@ "testing", "xunit" ], - "time": "2018-09-08T15:10:43+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "5.0.10", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.0", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.1" - }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.5.11" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "abandoned": true, - "time": "2018-08-09T05:50:03+00:00" + "time": "2019-10-07T12:57:41+00:00" }, { "name": "psr/container", @@ -1520,30 +1414,30 @@ }, { "name": "sebastian/comparator", - "version": "2.1.3", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/diff": "^2.0 || ^3.0", + "php": "^7.1", + "sebastian/diff": "^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1580,32 +1474,33 @@ "compare", "equality" ], - "time": "2018-02-01T13:46:46+00:00" + "time": "2018-07-12T15:12:46+00:00" }, { "name": "sebastian/diff", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1630,34 +1525,40 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", - "version": "3.1.0", + "version": "4.2.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404", + "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.1" + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -1682,20 +1583,20 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "time": "2019-05-05T09:05:15+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { @@ -1722,6 +1623,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -1730,17 +1635,13 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -1749,7 +1650,7 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2019-09-14T09:02:43+00:00" }, { "name": "sebastian/finder-facade", @@ -1790,71 +1691,28 @@ "homepage": "https://github.com/sebastianbergmann/finder-facade", "time": "2017-11-18T17:31:49+00:00" }, - { - "name": "sebastian/git", - "version": "2.1.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/git.git", - "reference": "815bbbc963cf35e5413df195aa29df58243ecd24" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/git/zipball/815bbbc963cf35e5413df195aa29df58243ecd24", - "reference": "815bbbc963cf35e5413df195aa29df58243ecd24", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Simple wrapper for Git", - "homepage": "http://www.github.com/sebastianbergmann/git", - "keywords": [ - "git" - ], - "abandoned": true, - "time": "2017-01-23T20:57:12+00:00" - }, { "name": "sebastian/global-state", - "version": "2.0.0", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "ext-dom": "*", + "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" @@ -1862,7 +1720,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1885,7 +1743,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "time": "2019-02-01T05:30:01+00:00" }, { "name": "sebastian/object-enumerator", @@ -1981,21 +1839,22 @@ }, { "name": "sebastian/phpcpd", - "version": "3.0.1", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpcpd.git", - "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564" + "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/dfed51c1288790fc957c9433e2f49ab152e8a564", - "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/0d9afa762f2400de077b2192f4a9d127de0bb78e", + "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e", "shasum": "" }, "require": { - "php": "^5.6|^7.0", - "phpunit/php-timer": "^1.0.6", + "ext-dom": "*", + "php": "^7.1", + "phpunit/php-timer": "^2.0", "sebastian/finder-facade": "^1.1", "sebastian/version": "^1.0|^2.0", "symfony/console": "^2.7|^3.0|^4.0" @@ -2006,7 +1865,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -2027,7 +1886,7 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2017-11-16T08:49:28+00:00" + "time": "2018-09-17T17:17:27+00:00" }, { "name": "sebastian/recursion-context", @@ -2084,25 +1943,25 @@ }, { "name": "sebastian/resource-operations", - "version": "1.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -2122,7 +1981,53 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2018-10-04T04:07:39+00:00" + }, + { + "name": "sebastian/type", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "time": "2019-07-02T08:10:15+00:00" }, { "name": "sebastian/version", @@ -2169,16 +2074,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.3.2", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e" + "reference": "0afebf16a2e7f1e434920fa976253576151effe9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6ad28354c04b364c3c71a34e4a18b629cc3b231e", - "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/0afebf16a2e7f1e434920fa976253576151effe9", + "reference": "0afebf16a2e7f1e434920fa976253576151effe9", "shasum": "" }, "require": { @@ -2211,41 +2116,41 @@ } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", "standards" ], - "time": "2018-09-23T23:08:17+00:00" + "time": "2019-09-26T23:12:26+00:00" }, { "name": "symfony/config", - "version": "v3.4.23", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "177a276c01575253c95cefe0866e3d1b57637fe0" + "reference": "0acb26407a9e1a64a275142f0ae5e36436342720" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/177a276c01575253c95cefe0866e3d1b57637fe0", - "reference": "177a276c01575253c95cefe0866e3d1b57637fe0", + "url": "https://api.github.com/repos/symfony/config/zipball/0acb26407a9e1a64a275142f0ae5e36436342720", + "reference": "0acb26407a9e1a64a275142f0ae5e36436342720", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0", + "php": "^7.1.3", + "symfony/filesystem": "~3.4|~4.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/dependency-injection": "<3.3", - "symfony/finder": "<3.3" + "symfony/finder": "<3.4" }, "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/event-dispatcher": "~3.3|~4.0", - "symfony/finder": "~3.3|~4.0", - "symfony/yaml": "~3.0|~4.0" + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/finder": "~3.4|~4.0", + "symfony/messenger": "~4.1", + "symfony/yaml": "~3.4|~4.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -2253,7 +2158,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2280,29 +2185,31 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2019-02-23T15:06:07+00:00" + "time": "2019-09-19T15:51:53+00:00" }, { "name": "symfony/console", - "version": "v3.4.23", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "71ce77f37af0c5ffb9590e43cc4f70e426945c5e" + "reference": "929ddf360d401b958f611d44e726094ab46a7369" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/71ce77f37af0c5ffb9590e43cc4f70e426945c5e", - "reference": "71ce77f37af0c5ffb9590e43cc4f70e426945c5e", + "url": "https://api.github.com/repos/symfony/console/zipball/929ddf360d401b958f611d44e726094ab46a7369", + "reference": "929ddf360d401b958f611d44e726094ab46a7369", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/debug": "~2.8|~3.0|~4.0", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1" }, "conflict": { "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3", "symfony/process": "<3.3" }, "provide": { @@ -2310,11 +2217,12 @@ }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.3|~4.0", + "symfony/config": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", + "symfony/event-dispatcher": "^4.3", "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.3|~4.0" + "symfony/process": "~3.4|~4.0", + "symfony/var-dumper": "^4.3" }, "suggest": { "psr/log": "For using the console logger", @@ -2325,7 +2233,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2352,94 +2260,40 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-02-23T15:06:07+00:00" + "time": "2019-10-07T12:36:49+00:00" }, { - "name": "symfony/debug", - "version": "v4.2.4", + "name": "symfony/dependency-injection", + "version": "v4.3.5", "source": { "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "de73f48977b8eaf7ce22814d66e43a1662cc864f" + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "e1e0762a814b957a1092bff75a550db49724d05b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/de73f48977b8eaf7ce22814d66e43a1662cc864f", - "reference": "de73f48977b8eaf7ce22814d66e43a1662cc864f", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e1e0762a814b957a1092bff75a550db49724d05b", + "reference": "e1e0762a814b957a1092bff75a550db49724d05b", "shasum": "" }, "require": { "php": "^7.1.3", - "psr/log": "~1.0" + "psr/container": "^1.0", + "symfony/service-contracts": "^1.1.6" }, "conflict": { - "symfony/http-kernel": "<3.4" - }, - "require-dev": { - "symfony/http-kernel": "~3.4|~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.2-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Debug\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Debug Component", - "homepage": "https://symfony.com", - "time": "2019-03-03T18:11:24+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v3.4.23", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "c3dd7b7ea8cd8ec12304a5e222d7dc01cac8fa11" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c3dd7b7ea8cd8ec12304a5e222d7dc01cac8fa11", - "reference": "c3dd7b7ea8cd8ec12304a5e222d7dc01cac8fa11", - "shasum": "" - }, - "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" - }, - "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", + "symfony/config": "<4.3", + "symfony/finder": "<3.4", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" }, "provide": { - "psr/container-implementation": "1.0" + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0" }, "require-dev": { - "symfony/config": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", + "symfony/config": "^4.3", + "symfony/expression-language": "~3.4|~4.0", "symfony/yaml": "~3.4|~4.0" }, "suggest": { @@ -2452,7 +2306,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2479,30 +2333,30 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2019-02-23T15:06:07+00:00" + "time": "2019-10-02T12:58:58+00:00" }, { "name": "symfony/filesystem", - "version": "v3.4.23", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "acf99758b1df8e9295e6b85aa69f294565c9fedb" + "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/acf99758b1df8e9295e6b85aa69f294565c9fedb", - "reference": "acf99758b1df8e9295e6b85aa69f294565c9fedb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/9abbb7ef96a51f4d7e69627bc6f63307994e4263", + "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2529,20 +2383,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2019-02-04T21:34:32+00:00" + "time": "2019-08-20T14:07:54+00:00" }, { "name": "symfony/finder", - "version": "v4.2.4", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a" + "reference": "5e575faa95548d0586f6bedaeabec259714e44d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/267b7002c1b70ea80db0833c3afe05f0fbde580a", - "reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a", + "url": "https://api.github.com/repos/symfony/finder/zipball/5e575faa95548d0586f6bedaeabec259714e44d1", + "reference": "5e575faa95548d0586f6bedaeabec259714e44d1", "shasum": "" }, "require": { @@ -2551,7 +2405,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2578,20 +2432,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-02-23T15:42:05+00:00" + "time": "2019-09-16T11:29:48+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.10.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", "shasum": "" }, "require": { @@ -2603,7 +2457,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -2620,12 +2474,12 @@ ], "authors": [ { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { - "name": "Gert de Pagter", - "email": "backendtea@gmail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -2636,20 +2490,20 @@ "polyfill", "portable" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.10.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17", "shasum": "" }, "require": { @@ -2661,7 +2515,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -2695,7 +2549,123 @@ "portable", "shim" ], - "time": "2018-09-21T13:07:52+00:00" + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/2ceb49eaccb9352bff54d22570276bb75ba4a188", + "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v1.1.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "ffcde9615dc5bb4825b9f6aed07716f1f57faae0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffcde9615dc5bb4825b9f6aed07716f1f57faae0", + "reference": "ffcde9615dc5bb4825b9f6aed07716f1f57faae0", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T11:12:18+00:00" }, { "name": "theseer/directoryscanner", @@ -2826,16 +2796,16 @@ }, { "name": "theseer/phpdox", - "version": "0.11.2", + "version": "0.12.0", "source": { "type": "git", "url": "https://github.com/theseer/phpdox.git", - "reference": "0e1dbf4bd862ed0cf87797409407973b2c228958" + "reference": "a46438e723a2b5bfd6ea4f299ecc0c7a1db1112c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/phpdox/zipball/0e1dbf4bd862ed0cf87797409407973b2c228958", - "reference": "0e1dbf4bd862ed0cf87797409407973b2c228958", + "url": "https://api.github.com/repos/theseer/phpdox/zipball/a46438e723a2b5bfd6ea4f299ecc0c7a1db1112c", + "reference": "a46438e723a2b5bfd6ea4f299ecc0c7a1db1112c", "shasum": "" }, "require": { @@ -2845,9 +2815,9 @@ "ext-mbstring": "*", "ext-tokenizer": "*", "ext-xsl": "*", - "nikic/php-parser": "^3.1", - "php": ">=5.5", - "phpunit/php-timer": "^1.0", + "nikic/php-parser": "^4.2", + "php": ">=7.1", + "phpunit/php-timer": "^2.0", "theseer/directoryscanner": "^1.3.0", "theseer/fdomdocument": "^1.6", "theseer/fxsl": "^1.1" @@ -2873,20 +2843,20 @@ } ], "description": "A fast Documentation generator for PHP Code using standard technology (SRC, DOCBLOCK, XML and XSLT) with event based processing", - "time": "2018-05-22T16:43:30+00:00" + "time": "2019-03-13T09:34:17+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { @@ -2913,20 +2883,20 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "time": "2019-06-13T22:48:21+00:00" }, { "name": "webmozart/assert", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", + "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", "shasum": "" }, "require": { @@ -2934,8 +2904,7 @@ "symfony/polyfill-ctype": "^1.8" }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", "extra": { @@ -2964,7 +2933,7 @@ "check", "validate" ], - "time": "2018-12-25T11:19:39+00:00" + "time": "2019-08-24T08:43:50+00:00" } ], "aliases": [], @@ -2973,7 +2942,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.6", + "php": ">=7.0", "ext-session": "*", "ext-ctype": "*", "ext-pdo": "*", @@ -2988,7 +2957,7 @@ "ext-openssl": "*" }, "platform-dev": { - "php": ">=7.1", + "php": ">=7.3", "ext-pcntl": "*" } } diff --git a/customer_domains.php b/customer_domains.php index 0e44156f..e50173e1 100644 --- a/customer_domains.php +++ b/customer_domains.php @@ -369,7 +369,7 @@ if ($page == 'overview') { $domains .= \Froxlor\UI\HTML::makeoption($idna_convert->decode($row_domain['domain']), $row_domain['id'], $result['aliasdomain']); } - if (preg_match('/^https?\:\/\//', $result['documentroot']) && \Froxlor\Validate\Form\Data::validateUrl($result['documentroot'])) { + if (preg_match('/^https?\:\/\//', $result['documentroot']) && \Froxlor\Validate\Validate::validateUrl($result['documentroot'])) { if (Settings::Get('panel.pathedit') == 'Dropdown') { $urlvalue = $result['documentroot']; $pathSelect = \Froxlor\FileDir::makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']); @@ -480,6 +480,17 @@ if ($page == 'overview') { } elseif ($page == 'domainssleditor') { if ($action == '' || $action == 'view') { + + // get domain + try { + $json_result = SubDomains::getLocal($userinfo, array( + 'id' => $id + ))->get(); + } catch (Exception $e) { + \Froxlor\UI\Response::dynamic_error($e->getMessage()); + } + $result_domain = json_decode($json_result, true)['data']; + if (isset($_POST['send']) && $_POST['send'] == 'send') { $do_insert = isset($_POST['do_insert']) ? (($_POST['do_insert'] == 1) ? true : false) : false; try { diff --git a/customer_index.php b/customer_index.php index d73f2555..a164a16e 100644 --- a/customer_index.php +++ b/customer_index.php @@ -93,11 +93,19 @@ if ($page == 'overview') { 'cid' => $userinfo['customerid'] )); + if ($usages) + { + $userinfo['diskspace_used'] = round($usages['webspace'] / 1024, Settings::Get('panel.decimal_places')); + $userinfo['mailspace_used'] = round($usages['mail'] / 1024, Settings::Get('panel.decimal_places')); + $userinfo['dbspace_used'] = round($usages['mysql'] / 1024, Settings::Get('panel.decimal_places')); + $userinfo['total_used'] = round(($usages['webspace'] + $usages['mail'] + $usages['mysql']) / 1024, Settings::Get('panel.decimal_places')); + } else { + $userinfo['diskspace_used'] = 0; + $userinfo['mailspace_used'] = 0; + $userinfo['dbspace_used'] = 0; + $userinfo['total_used'] = 0; + } $userinfo['diskspace'] = round($userinfo['diskspace'] / 1024, Settings::Get('panel.decimal_places')); - $userinfo['diskspace_used'] = round($usages['webspace'] / 1024, Settings::Get('panel.decimal_places')); - $userinfo['mailspace_used'] = round($usages['mail'] / 1024, Settings::Get('panel.decimal_places')); - $userinfo['dbspace_used'] = round($usages['mysql'] / 1024, Settings::Get('panel.decimal_places')); - $userinfo['traffic'] = round($userinfo['traffic'] / (1024 * 1024), Settings::Get('panel.decimal_places')); $userinfo['traffic_used'] = round($userinfo['traffic_used'] / (1024 * 1024), Settings::Get('panel.decimal_places')); $userinfo = \Froxlor\PhpHelper::strReplaceArray('-1', $lng['customer']['unlimited'], $userinfo, 'diskspace traffic mysqls emails email_accounts email_forwarders email_quota ftps subdomains'); @@ -114,6 +122,8 @@ if ($page == 'overview') { $se[] = "PHP"; if ($userinfo['perlenabled'] == '1') $se[] = "Perl/CGI"; + if ($userinfo['api_allowed'] == '1') + $se[] = 'API'; $services_enabled = implode(", ", $se); eval("echo \"" . \Froxlor\UI\Template::getTemplate('index/index') . "\";"); @@ -353,8 +363,6 @@ if ($page == 'overview') { } } elseif ($page == 'apikeys' && Settings::Get('api.enabled') == 1) { require_once __DIR__ . '/api_keys.php'; -} elseif ($page == 'apihelp' && Settings::Get('api.enabled') == 1) { - require_once __DIR__ . '/apihelp.php'; } elseif ($page == '2fa' && Settings::Get('2fa.enabled') == 1) { require_once __DIR__ . '/2fa.php'; } diff --git a/customer_logger.php b/customer_logger.php index 01da2095..197e99a2 100644 --- a/customer_logger.php +++ b/customer_logger.php @@ -96,7 +96,7 @@ if ($page == 'log') { case \Froxlor\FroxlorLogger::LOGIN_ACTION: $_action = $lng['logger']['login']; break; - case LOG_ERROR: + case \Froxlor\FroxlorLogger::LOG_ERROR: $_action = $lng['logger']['intern']; break; default: diff --git a/dns_editor.php b/dns_editor.php index c1d28546..77f121ef 100644 --- a/dns_editor.php +++ b/dns_editor.php @@ -108,11 +108,16 @@ if (! empty($dom_entries)) { $type_select_values = array( 'A', 'AAAA', - 'NS', + 'CAA', + 'CNAME', + 'DNAME', + 'LOC', 'MX', + 'NS', + 'RP', 'SRV', + 'SSHFP', 'TXT', - 'CNAME' ); asort($type_select_values); foreach ($type_select_values as $_type) { diff --git a/doc/example/FroxlorAPI.php b/doc/example/FroxlorAPI.php index 8bcb742d..9b2ef050 100644 --- a/doc/example/FroxlorAPI.php +++ b/doc/example/FroxlorAPI.php @@ -148,6 +148,11 @@ class FroxlorAPI */ public function getLastResponse(): array { + if (!empty($this->getLastError())) { + // nothing is returned when the last call + // was not successful + return []; + } return $this->last_body; } diff --git a/install/froxlor.sql b/install/froxlor.sql index 127fa073..d865fd88 100644 --- a/install/froxlor.sql +++ b/install/froxlor.sql @@ -132,6 +132,7 @@ CREATE TABLE `panel_admins` ( `custom_notes_show` tinyint(1) NOT NULL default '0', `type_2fa` tinyint(1) NOT NULL default '0', `data_2fa` varchar(500) NOT NULL default '', + `api_allowed` tinyint(1) NOT NULL default '1', PRIMARY KEY (`adminid`), UNIQUE KEY `loginname` (`loginname`) ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci; @@ -199,6 +200,7 @@ CREATE TABLE `panel_customers` ( `allowed_phpconfigs` varchar(500) NOT NULL default '', `type_2fa` tinyint(1) NOT NULL default '0', `data_2fa` varchar(500) NOT NULL default '', + `api_allowed` tinyint(1) NOT NULL default '1', `logviewenabled` tinyint(1) NOT NULL default '0', PRIMARY KEY (`customerid`), UNIQUE KEY `loginname` (`loginname`) @@ -246,6 +248,8 @@ CREATE TABLE `panel_domains` ( `speciallogfile` tinyint(1) NOT NULL default '0', `ssl_redirect` tinyint(4) NOT NULL default '0', `specialsettings` text, + `ssl_specialsettings` text, + `include_specialsettings` tinyint(1) NOT NULL default '0', `deactivated` tinyint(1) NOT NULL default '0', `bindserial` varchar(10) NOT NULL default '2000010100', `add_date` int( 11 ) NOT NULL default '0', @@ -264,6 +268,10 @@ CREATE TABLE `panel_domains` ( `notryfiles` tinyint(1) DEFAULT '0', `writeaccesslog` tinyint(1) DEFAULT '1', `writeerrorlog` tinyint(1) DEFAULT '1', + `override_tls` tinyint(1) DEFAULT '0', + `ssl_protocols` text, + `ssl_cipher_list` text, + `tlsv13_cipher_list` text, PRIMARY KEY (`id`), KEY `customerid` (`customerid`), KEY `parentdomain` (`parentdomainid`), @@ -289,6 +297,10 @@ CREATE TABLE `panel_ipsandports` ( `default_vhostconf_domain` text, `ssl_cert_chainfile` varchar(255) NOT NULL default '', `docroot` varchar(255) NOT NULL default '', + `ssl_specialsettings` text, + `include_specialsettings` tinyint(1) NOT NULL default '0', + `ssl_default_vhostconf_domain` text, + `include_default_vhostconf_domain` tinyint(1) NOT NULL default '0', PRIMARY KEY (`id`), UNIQUE KEY `ip_port` (`ip`,`port`) ) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci; @@ -375,6 +387,7 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES ('admin', 'show_news_feed', '0'), ('admin', 'show_version_login', '0'), ('admin', 'show_version_footer', '0'), + ('caa', 'caa_entry', ''), ('spf', 'use_spf', '0'), ('spf', 'spf_entry', '"v=spf1 a mx -all"'), ('dkim', 'dkim_algorithm', 'all'), @@ -404,7 +417,7 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES ('phpfpm', 'defaultini', '1'), ('phpfpm', 'vhost_defaultini', '2'), ('phpfpm', 'fastcgi_ipcdir', '/var/lib/apache2/fastcgi/'), - ('phpfpm', 'use_mod_proxy', '0'), + ('phpfpm', 'use_mod_proxy', '1'), ('phpfpm', 'ini_flags', 'asp_tags display_errors display_startup_errors @@ -561,6 +574,7 @@ opcache.interned_strings_buffer'), ('system', 'mod_fcgid_defaultini', '1'), ('system', 'ftpserver', 'proftpd'), ('system', 'dns_createmailentry', '0'), + ('system', 'dns_createcaaentry', '1'), ('system', 'froxlordirectlyviahostname', '0'), ('system', 'report_enable', '1'), ('system', 'report_webmax', '90'), @@ -613,7 +627,7 @@ opcache.interned_strings_buffer'), ('system', 'letsencryptkeysize', '4096'), ('system', 'letsencryptreuseold', 0), ('system', 'leenabled', '0'), - ('system', 'leapiversion', '1'), + ('system', 'leapiversion', '2'), ('system', 'backupenabled', '0'), ('system', 'dnsenabled', '0'), ('system', 'dns_server', 'Bind'), @@ -638,6 +652,7 @@ opcache.interned_strings_buffer'), ('system', 'nssextrausers', '0'), ('system', 'disable_le_selfcheck', '0'), ('system', 'ssl_protocols', 'TLSv1,TLSv1.2'), + ('system', 'tlsv13_cipher_list', ''), ('system', 'logfiles_format', ''), ('system', 'logfiles_type', '1'), ('system', 'logfiles_piped', '0'), @@ -680,8 +695,8 @@ opcache.interned_strings_buffer'), ('panel', 'password_special_char', '!?<>§$%+#=@'), ('panel', 'customer_hide_options', ''), ('panel', 'is_configured', '0'), - ('panel', 'version', '0.10.0-rc1'), - ('panel', 'db_version', '201904250'); + ('panel', 'version', '0.10.3'), + ('panel', 'db_version', '201910200'); DROP TABLE IF EXISTS `panel_tasks`; @@ -871,7 +886,7 @@ CREATE TABLE `panel_phpconfigs` ( INSERT INTO `panel_phpconfigs` (`id`, `description`, `binary`, `file_extensions`, `mod_fcgid_starter`, `mod_fcgid_maxrequests`, `phpsettings`) VALUES (1, 'Default Config', '/usr/bin/php-cgi', 'php', '-1', '-1', 'allow_call_time_pass_reference = Off\r\nallow_url_fopen = Off\r\nasp_tags = Off\r\ndisable_classes =\r\ndisable_functions = curl_exec,curl_multi_exec,exec,parse_ini_file,passthru,popen,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,shell_exec,show_source,system\r\ndisplay_errors = Off\r\ndisplay_startup_errors = Off\r\nenable_dl = Off\r\nerror_reporting = E_ALL & ~E_NOTICE\r\nexpose_php = Off\r\nfile_uploads = On\r\ncgi.force_redirect = 1\r\ngpc_order = "GPC"\r\nhtml_errors = Off\r\nignore_repeated_errors = Off\r\nignore_repeated_source = Off\r\ninclude_path = ".:{PEAR_DIR}"\r\nlog_errors = On\r\nlog_errors_max_len = 1024\r\nmagic_quotes_gpc = Off\r\nmagic_quotes_runtime = Off\r\nmagic_quotes_sybase = Off\r\nmax_execution_time = 30\r\nmax_input_time = 60\r\nmemory_limit = 128M\r\n{OPEN_BASEDIR_C}open_basedir = "{OPEN_BASEDIR}"\r\noutput_buffering = 4096\r\npost_max_size = 16M\r\nprecision = 14\r\nregister_argc_argv = Off\r\nregister_globals = Off\r\nreport_memleaks = On\r\nsendmail_path = "/usr/sbin/sendmail -t -i -f {CUSTOMER_EMAIL}"\r\nsession.auto_start = 0\r\nsession.bug_compat_42 = 0\r\nsession.bug_compat_warn = 1\r\nsession.cache_expire = 180\r\nsession.cache_limiter = nocache\r\nsession.cookie_domain =\r\nsession.cookie_lifetime = 0\r\nsession.cookie_path = /\r\nsession.entropy_file = /dev/urandom\r\nsession.entropy_length = 16\r\nsession.gc_divisor = 1000\r\nsession.gc_maxlifetime = 1440\r\nsession.gc_probability = 1\r\nsession.name = PHPSESSID\r\nsession.referer_check =\r\nsession.save_handler = files\r\nsession.save_path = "{TMP_DIR}"\r\nsession.serialize_handler = php\r\nsession.use_cookies = 1\r\nsession.use_trans_sid = 0\r\nshort_open_tag = On\r\nsuhosin.mail.protect = 1\r\nsuhosin.simulation = Off\r\ntrack_errors = Off\r\nupload_max_filesize = 32M\r\nupload_tmp_dir = "{TMP_DIR}"\r\nvariables_order = "GPCS"\r\n;mail.add_x_header = On\r\n;mail.log = "/var/log/phpmail.log"\r\nopcache.restrict_api = "{DOCUMENT_ROOT}"\r\n'), -(2, 'Froxlor Vhost Config', '/usr/bin/php-cgi', 'php', '-1', '-1', 'allow_call_time_pass_reference = Off\r\nallow_url_fopen = On\r\nasp_tags = Off\r\ndisable_classes =\r\ndisable_functions = curl_multi_exec,exec,parse_ini_file,passthru,popen,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,shell_exec,show_source,system\r\ndisplay_errors = Off\r\ndisplay_startup_errors = Off\r\nenable_dl = Off\r\nerror_reporting = E_ALL & ~E_NOTICE\r\nexpose_php = Off\r\nfile_uploads = On\r\ncgi.force_redirect = 1\r\ngpc_order = "GPC"\r\nhtml_errors = Off\r\nignore_repeated_errors = Off\r\nignore_repeated_source = Off\r\ninclude_path = ".:{PEAR_DIR}"\r\nlog_errors = On\r\nlog_errors_max_len = 1024\r\nmagic_quotes_gpc = Off\r\nmagic_quotes_runtime = Off\r\nmagic_quotes_sybase = Off\r\nmax_execution_time = 60\r\nmax_input_time = 60\r\nmemory_limit = 128M\r\noutput_buffering = 4096\r\npost_max_size = 16M\r\nprecision = 14\r\nregister_argc_argv = Off\r\nregister_globals = Off\r\nreport_memleaks = On\r\nsendmail_path = "/usr/sbin/sendmail -t -i -f {CUSTOMER_EMAIL}"\r\nsession.auto_start = 0\r\nsession.bug_compat_42 = 0\r\nsession.bug_compat_warn = 1\r\nsession.cache_expire = 180\r\nsession.cache_limiter = nocache\r\nsession.cookie_domain =\r\nsession.cookie_lifetime = 0\r\nsession.cookie_path = /\r\nsession.entropy_file = /dev/urandom\r\nsession.entropy_length = 16\r\nsession.gc_divisor = 1000\r\nsession.gc_maxlifetime = 1440\r\nsession.gc_probability = 1\r\nsession.name = PHPSESSID\r\nsession.referer_check =\r\nsession.save_handler = files\r\nsession.save_path = "{TMP_DIR}"\r\nsession.serialize_handler = php\r\nsession.use_cookies = 1\r\nsession.use_trans_sid = 0\r\nshort_open_tag = On\r\nsuhosin.mail.protect = 1\r\nsuhosin.simulation = Off\r\ntrack_errors = Off\r\nupload_max_filesize = 32M\r\nupload_tmp_dir = "{TMP_DIR}"\r\nvariables_order = "GPCS"\r\n;mail.add_x_header = On\r\n;mail.log = "/var/log/phpmail.log"\r\nopcache.restrict_api = ""\r\n'); +(2, 'Froxlor Vhost Config', '/usr/bin/php-cgi', 'php', '-1', '-1', 'allow_call_time_pass_reference = Off\r\nallow_url_fopen = On\r\nasp_tags = Off\r\ndisable_classes =\r\ndisable_functions = curl_multi_exec,parse_ini_file,passthru,popen,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,shell_exec,show_source,system\r\ndisplay_errors = Off\r\ndisplay_startup_errors = Off\r\nenable_dl = Off\r\nerror_reporting = E_ALL & ~E_NOTICE\r\nexpose_php = Off\r\nfile_uploads = On\r\ncgi.force_redirect = 1\r\ngpc_order = "GPC"\r\nhtml_errors = Off\r\nignore_repeated_errors = Off\r\nignore_repeated_source = Off\r\ninclude_path = ".:{PEAR_DIR}"\r\nlog_errors = On\r\nlog_errors_max_len = 1024\r\nmagic_quotes_gpc = Off\r\nmagic_quotes_runtime = Off\r\nmagic_quotes_sybase = Off\r\nmax_execution_time = 60\r\nmax_input_time = 60\r\nmemory_limit = 128M\r\noutput_buffering = 4096\r\npost_max_size = 16M\r\nprecision = 14\r\nregister_argc_argv = Off\r\nregister_globals = Off\r\nreport_memleaks = On\r\nsendmail_path = "/usr/sbin/sendmail -t -i -f {CUSTOMER_EMAIL}"\r\nsession.auto_start = 0\r\nsession.bug_compat_42 = 0\r\nsession.bug_compat_warn = 1\r\nsession.cache_expire = 180\r\nsession.cache_limiter = nocache\r\nsession.cookie_domain =\r\nsession.cookie_lifetime = 0\r\nsession.cookie_path = /\r\nsession.entropy_file = /dev/urandom\r\nsession.entropy_length = 16\r\nsession.gc_divisor = 1000\r\nsession.gc_maxlifetime = 1440\r\nsession.gc_probability = 1\r\nsession.name = PHPSESSID\r\nsession.referer_check =\r\nsession.save_handler = files\r\nsession.save_path = "{TMP_DIR}"\r\nsession.serialize_handler = php\r\nsession.use_cookies = 1\r\nsession.use_trans_sid = 0\r\nshort_open_tag = On\r\nsuhosin.mail.protect = 1\r\nsuhosin.simulation = Off\r\ntrack_errors = Off\r\nupload_max_filesize = 32M\r\nupload_tmp_dir = "{TMP_DIR}"\r\nvariables_order = "GPCS"\r\n;mail.add_x_header = On\r\n;mail.log = "/var/log/phpmail.log"\r\nopcache.restrict_api = ""\r\n'); DROP TABLE IF EXISTS `cronjobs_run`; diff --git a/install/install.php b/install/install.php index 1e06c9d1..7a258149 100644 --- a/install/install.php +++ b/install/install.php @@ -15,6 +15,14 @@ * @package Install * */ +if (! file_exists(dirname(__DIR__) . '/vendor/autoload.php')) { + // get hint-template + $vendor_hint = file_get_contents(dirname(__DIR__) . '/templates/Sparkle/misc/vendormissinghint.tpl'); + // replace values + $vendor_hint = str_replace("", dirname(__DIR__), $vendor_hint); + $vendor_hint = str_replace("", date('Y', time()), $vendor_hint); + die($vendor_hint); +} require dirname(__DIR__) . '/vendor/autoload.php'; require __DIR__ . '/lib/class.FroxlorInstall.php'; diff --git a/install/lib/class.FroxlorInstall.php b/install/lib/class.FroxlorInstall.php index ba101c35..ddc3166a 100644 --- a/install/lib/class.FroxlorInstall.php +++ b/install/lib/class.FroxlorInstall.php @@ -104,7 +104,7 @@ class FroxlorInstall // check if we have a valid installation already $this->_checkUserdataFile(); // include the MySQL-Table-Definitions - require $this->_basepath . '/lib/tables.inc.php'; + require_once $this->_basepath . '/lib/tables.inc.php'; // include language $this->_includeLanguageFile(); // show the action @@ -407,6 +407,7 @@ class FroxlorInstall `name` = 'Froxlor-Administrator', `email` = :email, `def_language` = :deflang, + `api_allowed` = 1, `customers` = -1, `customers_see_all` = 1, `caneditphpsettings` = 1, @@ -643,21 +644,8 @@ class FroxlorInstall $mysql_access_host_array[] = $this->_data['serverip']; foreach ($mysql_access_host_array as $mysql_access_host) { - $_db = str_replace('`', '', $this->_data['mysql_database']); - $stmt = $db_root->prepare(" - GRANT ALL PRIVILEGES ON `" . $_db . "`.* - TO :username@:host - IDENTIFIED BY 'password'"); - $stmt->execute(array( - "username" => $this->_data['mysql_unpriv_user'], - "host" => $mysql_access_host - )); - $stmt = $db_root->prepare("SET PASSWORD FOR :username@:host = PASSWORD(:password)"); - $stmt->execute(array( - "username" => $this->_data['mysql_unpriv_user'], - "host" => $mysql_access_host, - "password" => $this->_data['mysql_unpriv_pass'] - )); + $frox_db = str_replace('`', '', $this->_data['mysql_database']); + $this->_grantDbPrivilegesTo($db_root, $frox_db, $this->_data['mysql_unpriv_user'], $this->_data['mysql_unpriv_pass'], $mysql_access_host); } $db_root->query("FLUSH PRIVILEGES;"); @@ -667,6 +655,38 @@ class FroxlorInstall return $content; } + private function _grantDbPrivilegesTo(&$db_root, $database, $username, $password, $access_host) + { + // mysql8 compatibility + if (version_compare($db_root->getAttribute(\PDO::ATTR_SERVER_VERSION), '8.0.11', '>=')) { + // create user + $stmt = $db_root->prepare(" + CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED BY :password + "); + $stmt->execute(array( + "password" => $password + )); + // grant privileges + $stmt = $db_root->prepare(" + GRANT ALL ON `" . $database . "`.* TO :username@:host + "); + $stmt->execute(array( + "username" => $username, + "host" => $access_host + )); + } else { + // grant privileges + $stmt = $db_root->prepare(" + GRANT ALL PRIVILEGES ON `" . $database . "`.* TO :username@:host IDENTIFIED BY :password + "); + $stmt->execute(array( + "username" => $username, + "host" => $access_host, + "password" => $password + )); + } + } + /** * Check if an old database exists and back it up if necessary * @@ -944,11 +964,11 @@ class FroxlorInstall // check for correct php version $content .= $this->_status_message('begin', $this->_lng['requirements']['phpversion']); - if (version_compare("5.6.0", PHP_VERSION, ">=")) { + if (version_compare("7.0.0", PHP_VERSION, ">=")) { $content .= $this->_status_message('red', $this->_lng['requirements']['notfound'] . ' (' . PHP_VERSION . ')'); $_die = true; } else { - if (version_compare("7.0.0", PHP_VERSION, ">=")) { + if (version_compare("7.1.0", PHP_VERSION, ">=")) { $content .= $this->_status_message('orange', $this->_lng['requirements']['newerphpprefered'] . ' (' . PHP_VERSION . ')'); } else { $content .= $this->_status_message('green', PHP_VERSION); @@ -1060,12 +1080,13 @@ class FroxlorInstall */ private function _sendHeaders() { - // no caching - header("Cache-Control: no-store, no-cache, must-revalidate"); - header("Pragma: no-cache"); - header('Last-Modified: ' . gmdate('D, d M Y H:i:s \G\M\T', time())); - header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time())); - + if (@php_sapi_name() !== 'cli') { + // no caching + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Pragma: no-cache"); + header('Last-Modified: ' . gmdate('D, d M Y H:i:s \G\M\T', time())); + header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time())); + } // ensure that default timezone is set if (function_exists("date_default_timezone_set") && function_exists("date_default_timezone_get")) { @date_default_timezone_set(@date_default_timezone_get()); @@ -1082,7 +1103,7 @@ class FroxlorInstall if (file_exists($userdata)) { // includes the usersettings (MySQL-Username/Passwort) // to test if Froxlor is already installed - require $this->_basepath . '/lib/userdata.inc.php'; + require_once $this->_basepath . '/lib/userdata.inc.php'; if (isset($sql) && is_array($sql)) { // use sparkle theme for the notice @@ -1126,7 +1147,7 @@ class FroxlorInstall $lngfile = $this->_basepath . '/install/lng/' . $standardlanguage . '.lng.php'; if (file_exists($lngfile)) { // includes file /lng/$language.lng.php if it exists - require $lngfile; + require_once $lngfile; $this->_lng = $lng; } @@ -1135,7 +1156,7 @@ class FroxlorInstall $lngfile = $this->_basepath . '/install/lng/' . $this->_activelng . '.lng.php'; if (file_exists($lngfile)) { // includes file /lng/$language.lng.php if it exists - require $lngfile; + require_once $lngfile; $this->_lng = $lng; } } diff --git a/install/lng/english.lng.php b/install/lng/english.lng.php index 4665033b..b7dd5ef8 100644 --- a/install/lng/english.lng.php +++ b/install/lng/english.lng.php @@ -22,8 +22,8 @@ $lng['requirements']['not_true'] = 'no'; $lng['requirements']['notfound'] = 'not found'; $lng['requirements']['notinstalled'] = 'not installed'; $lng['requirements']['activated'] = 'enabled'; -$lng['requirements']['phpversion'] = 'PHP version >= 5.6'; -$lng['requirements']['newerphpprefered'] = 'Good, but php-7.0 is prefered.'; +$lng['requirements']['phpversion'] = 'PHP version >= 7.0'; +$lng['requirements']['newerphpprefered'] = 'Good, but php-7.1 is prefered.'; $lng['requirements']['phppdo'] = 'PHP PDO extension and PDO-MySQL driver...'; $lng['requirements']['phpsession'] = 'PHP session-extension...'; $lng['requirements']['phpctype'] = 'PHP ctype-extension...'; diff --git a/install/lng/french.lng.php b/install/lng/french.lng.php index ab44f688..fdb733ce 100644 --- a/install/lng/french.lng.php +++ b/install/lng/french.lng.php @@ -22,7 +22,7 @@ $lng['requirements']['not_true'] = 'non'; $lng['requirements']['notfound'] = 'introuvable'; $lng['requirements']['notinstalled'] = 'non installé'; $lng['requirements']['activated'] = 'activé'; -$lng['requirements']['phpversion'] = 'PHP version >= 5.6'; +$lng['requirements']['phpversion'] = 'PHP version >= 7.0'; $lng['requirements']['phppdo'] = 'extension PHP PDO et pilote PDO-MySQL ...'; $lng['requirements']['phpxml'] = 'extension PHP XML...'; $lng['requirements']['phpfilter'] = 'extension PHP filter ...'; diff --git a/install/lng/german.lng.php b/install/lng/german.lng.php index 0de1ff0e..1f95decc 100644 --- a/install/lng/german.lng.php +++ b/install/lng/german.lng.php @@ -22,8 +22,8 @@ $lng['requirements']['not_true'] = 'nein'; $lng['requirements']['notfound'] = 'nicht gefunden'; $lng['requirements']['notinstalled'] = 'nicht installiert'; $lng['requirements']['activated'] = 'ist aktiviert.'; -$lng['requirements']['phpversion'] = 'PHP Version >= 5.6'; -$lng['requirements']['newerphpprefered'] = 'Passt, aber php-7.0 wird bevorzugt.'; +$lng['requirements']['phpversion'] = 'PHP Version >= 7.0'; +$lng['requirements']['newerphpprefered'] = 'Passt, aber php-7.1 wird bevorzugt.'; $lng['requirements']['phppdo'] = 'PHP PDO Erweiterung und PDO-MySQL Treiber...'; $lng['requirements']['phpsession'] = 'PHP session-Erweiterung...'; $lng['requirements']['phpctype'] = 'PHP ctype-Erweiterung...'; 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 c4796636..7e412fb0 100644 --- a/install/updates/froxlor/0.10/update_0.10.inc.php +++ b/install/updates/froxlor/0.10/update_0.10.inc.php @@ -220,6 +220,14 @@ if (\Froxlor\Froxlor::isDatabaseVersion('201902120')) { $domain_in = substr($domain_in, 0, - 1); Database::query("DELETE FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` IN (" . $domain_in . ")"); } + // check for froxlor domain using let's encrypt + if (Settings::Get('system.le_froxlor_enabled') == 1) { + Database::query("DELETE FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` WHERE `domainid` = '0'"); + } + lastStepStatus(0); + + showUpdateStep("Inserting job to regenerate configfiles"); + \Froxlor\System\Cronjob::inserttask('1'); lastStepStatus(0); \Froxlor\Froxlor::updateToDbVersion('201902170'); @@ -255,3 +263,187 @@ if (\Froxlor\Froxlor::isDatabaseVersion('201904100')) { \Froxlor\Froxlor::updateToDbVersion('201904250'); } + +if (\Froxlor\Froxlor::isFroxlorVersion('0.10.0-rc1')) { + showUpdateStep("Updating from 0.10.0-rc1 to 0.10.0-rc2", false); + \Froxlor\Froxlor::updateToVersion('0.10.0-rc2'); +} + +if (\Froxlor\Froxlor::isDatabaseVersion('201904250')) { + + showUpdateStep("Adding new settings for CAA"); + Settings::AddNew('caa.caa_entry', '', true); + Settings::AddNew('system.dns_createcaaentry', 1, true); + lastStepStatus(0); + + \Froxlor\Froxlor::updateToDbVersion('201907270'); +} + +if (\Froxlor\Froxlor::isDatabaseVersion('201907270')) { + + showUpdateStep("Cleaning up old files"); + $to_clean = array( + "actions/admin/settings/000.version.php", + "actions/admin/settings/190.ticket.php", + "admin_tickets.php", + "customer_tickets.php", + "install/scripts/language-check.php", + "install/updates/froxlor/upgrade_syscp.inc.php", + "lib/classes", + "lib/configfiles/precise.xml", + "lib/cron_init.php", + "lib/cron_shutdown.php", + "lib/formfields/admin/tickets", + "lib/formfields/customer/tickets", + "lib/functions.php", + "lib/functions", + "lib/navigation/10.tickets.php", + "scripts/classes", + "scripts/jobs", + "templates/Sparkle/admin/tickets", + "templates/Sparkle/customer/tickets" + ); + $disabled = explode(',', ini_get('disable_functions')); + $exec_allowed = ! in_array('exec', $disabled); + $del_list = ""; + foreach ($to_clean as $filedir) { + $complete_filedir = \Froxlor\Froxlor::getInstallDir() . $filedir; + if (file_exists($complete_filedir)) { + if ($exec_allowed) { + Froxlor\FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir)); + } else { + $del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL; + } + } + } + if ($exec_allowed) { + lastStepStatus(0); + } else { + if (empty($del_list)) { + // none of the files existed + lastStepStatus(0); + } else { + lastStepStatus(1, 'manual commands needed'); + echo 'Please run the following commands manually:
' . $del_list . '

'; + } + } + + \Froxlor\Froxlor::updateToDbVersion('201909150'); +} + +if (\Froxlor\Froxlor::isFroxlorVersion('0.10.0-rc2')) { + showUpdateStep("Updating from 0.10.0-rc2 to 0.10.0 final", false); + \Froxlor\Froxlor::updateToVersion('0.10.0'); +} + +if (\Froxlor\Froxlor::isDatabaseVersion('201909150')) { + + showUpdateStep("Adding TLSv1.3-cipherlist setting"); + Settings::AddNew("system.tlsv13_cipher_list", ''); + lastStepStatus(0); + + \Froxlor\Froxlor::updateToDbVersion('201910030'); +} + +if (\Froxlor\Froxlor::isDatabaseVersion('201910030')) { + + showUpdateStep("Adding field api_allowed to admins and customers"); + Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` ADD `api_allowed` tinyint(1) NOT NULL default '1';"); + Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `api_allowed` tinyint(1) NOT NULL default '1';"); + lastStepStatus(0); + + \Froxlor\Froxlor::updateToDbVersion('201910090'); +} + +if (\Froxlor\Froxlor::isFroxlorVersion('0.10.0')) { + showUpdateStep("Updating from 0.10.0 to 0.10.1 final", false); + \Froxlor\Froxlor::updateToVersion('0.10.1'); +} + +if (\Froxlor\Froxlor::isDatabaseVersion('201910090')) { + + showUpdateStep("Adjusting Let's Encrypt API setting"); + Settings::Set("system.leapiversion", '2'); + lastStepStatus(0); + + \Froxlor\Froxlor::updateToDbVersion('201910110'); +} + +if (\Froxlor\Froxlor::isDatabaseVersion('201910110')) { + + showUpdateStep("Adding new settings for ssl-vhost default content"); + Settings::AddNew("system.default_sslvhostconf", ''); + Settings::AddNew("system.include_default_vhostconf", '0'); + lastStepStatus(0); + + showUpdateStep("Adding new fields to ips and ports-table"); + Database::query("ALTER TABLE `" . TABLE_PANEL_IPSANDPORTS . "` ADD `ssl_specialsettings` text AFTER `docroot`;"); + Database::query("ALTER TABLE `" . TABLE_PANEL_IPSANDPORTS . "` ADD `include_specialsettings` tinyint(1) NOT NULL default '0' AFTER `ssl_specialsettings`;"); + Database::query("ALTER TABLE `" . TABLE_PANEL_IPSANDPORTS . "` ADD `ssl_default_vhostconf_domain` text AFTER `include_specialsettings`;"); + Database::query("ALTER TABLE `" . TABLE_PANEL_IPSANDPORTS . "` ADD `include_default_vhostconf_domain` tinyint(1) NOT NULL default '0' AFTER `ssl_default_vhostconf_domain`;"); + lastStepStatus(0); + + showUpdateStep("Adding new fields to domains-table"); + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `ssl_specialsettings` text AFTER `specialsettings`;"); + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `include_specialsettings` tinyint(1) NOT NULL default '0' AFTER `ssl_specialsettings`;"); + lastStepStatus(0); + + // select all ips/ports with specialsettings and SSL enabled to include the specialsettings in the ssl-vhost + // because the former implementation included it and users might rely on that, see https://github.com/Froxlor/Froxlor/issues/727 + $sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_IPSANDPORTS . "` WHERE `specialsettings` <> '' AND `ssl` = '1'"); + Database::pexecute($sel_stmt); + $upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_IPSANDPORTS . "` SET `include_specialsettings` = '1' WHERE `id` = :id"); + if ($sel_stmt->columnCount() > 0) { + showUpdateStep("Adjusting IP/port settings for downward compatibility"); + while ($row = $sel_stmt->fetch(PDO::FETCH_ASSOC)) { + Database::pexecute($upd_stmt, [ + 'id' => $row['id'] + ]); + } + lastStepStatus(0); + } + + // select all domains with an ssl IP connected and specialsettings content to include these in the ssl-vhost + // to maintain former behavior + $sel_stmt = Database::prepare(" + SELECT d.id FROM `". TABLE_PANEL_DOMAINS . "` d + LEFT JOIN `". TABLE_DOMAINTOIP . "` d2i ON d2i.id_domain = d.id + LEFT JOIN `". TABLE_PANEL_IPSANDPORTS."` i ON i.id = d2i.id_ipandports + WHERE d.specialsettings <> '' AND i.ssl = '1' + "); + Database::pexecute($sel_stmt); + $upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `include_specialsettings` = '1' WHERE `id` = :id"); + if ($sel_stmt->columnCount() > 0) { + showUpdateStep("Adjusting domain settings for downward compatibility"); + while ($row = $sel_stmt->fetch(PDO::FETCH_ASSOC)) { + Database::pexecute($upd_stmt, [ + 'id' => $row['id'] + ]); + } + lastStepStatus(0); + } + + \Froxlor\Froxlor::updateToDbVersion('201910120'); +} + +if (\Froxlor\Froxlor::isFroxlorVersion('0.10.1')) { + showUpdateStep("Updating from 0.10.1 to 0.10.2", false); + \Froxlor\Froxlor::updateToVersion('0.10.2'); +} + +if (\Froxlor\Froxlor::isDatabaseVersion('201910120')) { + + showUpdateStep("Adding new TLS options to domains-table"); + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `override_tls` tinyint(1) DEFAULT '0' AFTER `writeerrorlog`;"); + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `ssl_protocols` text AFTER `override_tls`;"); + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `ssl_cipher_list` text AFTER `ssl_protocols`;"); + Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAINS . "` ADD `tlsv13_cipher_list` text AFTER `ssl_cipher_list`;"); + lastStepStatus(0); + + \Froxlor\Froxlor::updateToDbVersion('201910200'); +} + +if (\Froxlor\Froxlor::isFroxlorVersion('0.10.2')) { + showUpdateStep("Updating from 0.10.2 to 0.10.3", false); + \Froxlor\Froxlor::updateToVersion('0.10.3'); +} diff --git a/lib/Froxlor/Api/Commands/Admins.php b/lib/Froxlor/Api/Commands/Admins.php index a29ac9ad..72b7bb48 100644 --- a/lib/Froxlor/Api/Commands/Admins.php +++ b/lib/Froxlor/Api/Commands/Admins.php @@ -97,6 +97,8 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt * optional, default auto-generated * @param string $def_language * optional, default is system-default language + * @param bool $api_allowed + * optional, default is true if system setting api.enabled is true, else false * @param string $custom_notes * optional, default empty * @param bool $custom_notes_show @@ -171,6 +173,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt // parameters $def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage')); + $api_allowed = $this->getBoolParam('api_allowed', true, Settings::Get('api.enabled')); $custom_notes = $this->getParam('custom_notes', true, ''); $custom_notes_show = $this->getBoolParam('custom_notes_show', true, 0); $password = $this->getParam('admin_password', true, ''); @@ -271,6 +274,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt 'name' => $name, 'email' => $email, 'lang' => $def_language, + 'api_allowed' => $api_allowed, 'change_serversettings' => $change_serversettings, 'customers' => $customers, 'customers_see_all' => $customers_see_all, @@ -299,6 +303,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt `name` = :name, `email` = :email, `def_language` = :lang, + `api_allowed` = :api_allowed, `change_serversettings` = :change_serversettings, `customers` = :customers, `customers_see_all` = :customers_see_all, @@ -350,6 +355,8 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt * optional, default auto-generated * @param string $def_language * optional, default is system-default language + * @param bool $api_allowed + * optional, default is true if system setting api.enabled is true, else false * @param string $custom_notes * optional, default empty * @param string $theme @@ -444,6 +451,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt // you cannot edit some of the details of yourself if ($result['adminid'] == $this->getUserDetail('adminid')) { + $api_allowed = $result['api_allowed']; $deactivated = $result['deactivated']; $customers = $result['customers']; $domains = $result['domains']; @@ -462,6 +470,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt $traffic = $result['traffic']; $ipaddress = ($result['ip'] != - 1 ? json_decode($result['ip'], true) : - 1); } else { + $api_allowed = $this->getBoolParam('api_allowed', true, $result['api_allowed']); $deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']); $dec_places = Settings::Get('panel.decimal_places'); @@ -578,6 +587,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt 'name' => $name, 'email' => $email, 'lang' => $def_language, + 'api_allowed' => $api_allowed, 'change_serversettings' => $change_serversettings, 'customers' => $customers, 'customers_see_all' => $customers_see_all, @@ -607,6 +617,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt `name` = :name, `email` = :email, `def_language` = :lang, + `api_allowed` = :api_allowed, `change_serversettings` = :change_serversettings, `customers` = :customers, `customers_see_all` = :customers_see_all, @@ -793,7 +804,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt * @param string $extra * optional, default empty * @param int $increase_by - * optional, default 1 + * optional, default 1 */ public static function increaseUsage($adminid = 0, $resource = null, $extra = '', $increase_by = 1) { @@ -808,7 +819,7 @@ class Admins extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt * @param string $extra * optional, default empty * @param int $decrease_by - * optional, default 1 + * optional, default 1 */ public static function decreaseUsage($adminid = 0, $resource = null, $extra = '', $decrease_by = 1) { diff --git a/lib/Froxlor/Api/Commands/Certificates.php b/lib/Froxlor/Api/Commands/Certificates.php index a725a969..a9c46c9e 100644 --- a/lib/Froxlor/Api/Commands/Certificates.php +++ b/lib/Froxlor/Api/Commands/Certificates.php @@ -63,10 +63,19 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou $ssl_cert_chainfile = $this->getParam('ssl_cert_chainfile', true, ''); // validate whether the domain does not already have an entry - $result = $this->apiCall('Certificates.get', array( - 'id' => $domainid - )); - if (empty($result)) { + $has_cert = true; + try { + $this->apiCall('Certificates.get', array( + 'id' => $domainid + )); + } catch (\Exception $e) { + if ($e->getCode() == 412) { + $has_cert = false; + } else { + throw $e; + } + } + if (!$has_cert) { $this->addOrUpdateCertificate($domain['id'], $ssl_cert_file, $ssl_key_file, $ssl_ca_file, $ssl_cert_chainfile, true); $this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ssl-certificate for '" . $domain['domain'] . "'"); $result = $this->apiCall('Certificates.get', array( @@ -110,6 +119,9 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou $result = Database::pexecute_first($stmt, array( "domainid" => $domainid )); + if (! $result) { + throw new \Exception("Domain '" . $domain['domain'] . "' does not have a certificate.", 412); + } return $this->response(200, "successfull", $result); } @@ -271,6 +283,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou throw new \Exception("Unable to determine SSL certificate. Maybe no access?", 406); } + /** * insert or update certificates entry * @@ -292,6 +305,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou } $do_verify = true; + $expirationdate = null; // no cert-file given -> forget everything if ($ssl_cert_file == '') { $ssl_key_file = ''; @@ -332,6 +346,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou } else { \Froxlor\UI\Response::standard_error('sslcertificateinvalidcert', '', true); } + $expirationdate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']); } // Add/Update database entry @@ -345,7 +360,8 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou `ssl_cert_file` = :ssl_cert_file, `ssl_key_file` = :ssl_key_file, `ssl_ca_file` = :ssl_ca_file, - `ssl_cert_chainfile` = :ssl_cert_chainfile + `ssl_cert_chainfile` = :ssl_cert_chainfile, + `expirationdate` = :expirationdate " . $qrywhere . " `domainid`= :domainid "); $params = array( @@ -353,6 +369,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou "ssl_key_file" => $ssl_key_file, "ssl_ca_file" => $ssl_ca_file, "ssl_cert_chainfile" => $ssl_cert_chainfile, + "expirationdate" => $expirationdate, "domainid" => $domainid ); Database::pexecute($stmt, $params, true, true); diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index 271e1f6d..8d500f9b 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -136,6 +136,8 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource * optional * @param string $def_language, * optional, default is system-default language + * @param bool $api_allowed + * optional, default is true if system setting api.enabled is true, else false * @param int $gender * optional, 0 = no-gender, 1 = male, 2 = female * @param string $custom_notes @@ -197,11 +199,13 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource * @param bool $perlenabled * optional, whether to allow usage of Perl/CGI, default 0 (false) * @param bool $dnsenabled - * optional, ether to allow usage of the DNS editor (requires activated nameserver in settings), default 0 (false) + * optional, wether to allow usage of the DNS editor (requires activated nameserver in settings), default 0 (false) * @param bool $logviewenabled - * optional, ether to allow acccess to webserver access/error-logs, default 0 (false) + * optional, wether to allow acccess to webserver access/error-logs, default 0 (false) * @param bool $store_defaultindex * optional, whether to store the default index file to customers homedir + * @param int $hosting_plan_id + * optional, specify a hosting-plan to set certain resource-values from the plan instead of specifying them * * @access admin * @throws \Exception @@ -227,32 +231,61 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource $fax = $this->getParam('fax', true, ''); $customernumber = $this->getParam('customernumber', true, ''); $def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage')); + $api_allowed = $this->getBoolParam('api_allowed', true, Settings::Get('api.enabled')); $gender = (int) $this->getParam('gender', true, 0); $custom_notes = $this->getParam('custom_notes', true, ''); $custom_notes_show = $this->getBoolParam('custom_notes_show', true, 0); - - $diskspace = $this->getUlParam('diskspace', 'diskspace_ul', true, 0); - $traffic = $this->getUlParam('traffic', 'traffic_ul', true, 0); - $subdomains = $this->getUlParam('subdomains', 'subdomains_ul', true, 0); - $emails = $this->getUlParam('emails', 'emails_ul', true, 0); - $email_accounts = $this->getUlParam('email_accounts', 'email_accounts_ul', true, 0); - $email_forwarders = $this->getUlParam('email_forwarders', 'email_forwarders_ul', true, 0); - $email_quota = $this->getUlParam('email_quota', 'email_quota_ul', true, Settings::Get('system.mail_quota')); - $email_imap = $this->getBoolParam('email_imap', true, 0); - $email_pop3 = $this->getBoolParam('email_pop3', true, 0); - $ftps = $this->getUlParam('ftps', 'ftps_ul', true, 0); - $mysqls = $this->getUlParam('mysqls', 'mysqls_ul', true, 0); $createstdsubdomain = $this->getBoolParam('createstdsubdomain', true, 0); $password = $this->getParam('new_customer_password', true, ''); $sendpassword = $this->getBoolParam('sendpassword', true, 0); - $phpenabled = $this->getBoolParam('phpenabled', true, 0); - $p_allowed_phpconfigs = $this->getParam('allowed_phpconfigs', true, array()); - $perlenabled = $this->getBoolParam('perlenabled', true, 0); - $dnsenabled = $this->getBoolParam('dnsenabled', true, 0); - $logviewenabled = $this->getBoolParam('logviewenabled', true, 0); $store_defaultindex = $this->getBoolParam('store_defaultindex', true, 0); $loginname = $this->getParam('new_loginname', true, ''); + // hosting-plan values + $hosting_plan_id = $this->getParam('hosting_plan_id', true, 0); + if ($hosting_plan_id > 0) { + $hp_result = $this->apiCall('HostingPlans.get', array( + 'id' => $hosting_plan_id + )); + $hp_result['value'] = json_decode($hp_result['value'], true); + foreach ($hp_result['value'] as $index => $value) { + $hp_result[$index] = $value; + } + $diskspace = $hp_result['diskspace'] ?? 0; + $traffic = $hp_result['traffic'] ?? 0; + $subdomains = $hp_result['subdomains'] ?? 0; + $emails = $hp_result['emails'] ?? 0; + $email_accounts = $hp_result['email_accounts'] ?? 0; + $email_forwarders = $hp_result['email_forwarders'] ?? 0; + $email_quota = $hp_result['email_quota'] ?? Settings::Get('system.mail_quota'); + $email_imap = $hp_result['email_imap'] ?? 0; + $email_pop3 = $hp_result['email_pop3'] ?? 0; + $ftps = $hp_result['ftps'] ?? 0; + $mysqls = $hp_result['mysqls'] ?? 0; + $phpenabled = $hp_result['phpenabled'] ?? 0; + $p_allowed_phpconfigs = $hp_result['allowed_phpconfigs'] ?? 0; + $perlenabled = $hp_result['perlenabled'] ?? 0; + $dnsenabled = $hp_result['dnsenabled'] ?? 0; + $logviewenabled = $hp_result['logviewenabled'] ?? 0; + } else { + $diskspace = $this->getUlParam('diskspace', 'diskspace_ul', true, 0); + $traffic = $this->getUlParam('traffic', 'traffic_ul', true, 0); + $subdomains = $this->getUlParam('subdomains', 'subdomains_ul', true, 0); + $emails = $this->getUlParam('emails', 'emails_ul', true, 0); + $email_accounts = $this->getUlParam('email_accounts', 'email_accounts_ul', true, 0); + $email_forwarders = $this->getUlParam('email_forwarders', 'email_forwarders_ul', true, 0); + $email_quota = $this->getUlParam('email_quota', 'email_quota_ul', true, Settings::Get('system.mail_quota')); + $email_imap = $this->getBoolParam('email_imap', true, 0); + $email_pop3 = $this->getBoolParam('email_pop3', true, 0); + $ftps = $this->getUlParam('ftps', 'ftps_ul', true, 0); + $mysqls = $this->getUlParam('mysqls', 'mysqls_ul', true, 0); + $phpenabled = $this->getBoolParam('phpenabled', true, 0); + $p_allowed_phpconfigs = $this->getParam('allowed_phpconfigs', true, array()); + $perlenabled = $this->getBoolParam('perlenabled', true, 0); + $dnsenabled = $this->getBoolParam('dnsenabled', true, 0); + $logviewenabled = $this->getBoolParam('logviewenabled', true, 0); + } + // validation $name = \Froxlor\Validate\Validate::validate($name, 'name', '', '', array(), true); $firstname = \Froxlor\Validate\Validate::validate($firstname, 'first name', '', '', array(), true); @@ -340,11 +373,12 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource 'login' => $loginname ), true, true); + $mysql_maxlen = \Froxlor\Database\Database::getSqlUsernameLength() - strlen(Settings::Get('customer.mysqlprefix')); if (strtolower($loginname_check['loginname']) == strtolower($loginname) || strtolower($loginname_check_admin['loginname']) == strtolower($loginname)) { \Froxlor\UI\Response::standard_error('loginnameexists', $loginname, true); - } elseif (! \Froxlor\Validate\Validate::validateUsername($loginname, Settings::Get('panel.unix_names'), 14 - strlen(Settings::Get('customer.mysqlprefix')))) { - if (strlen($loginname) > 14 - strlen(Settings::Get('customer.mysqlprefix'))) { - \Froxlor\UI\Response::standard_error('loginnameiswrong2', 14 - strlen(Settings::Get('customer.mysqlprefix')), true); + } elseif (! \Froxlor\Validate\Validate::validateUsername($loginname, Settings::Get('panel.unix_names'), $mysql_maxlen)) { + if (strlen($loginname) > $mysql_maxlen) { + \Froxlor\UI\Response::standard_error('loginnameiswrong2', $mysql_maxlen, true); } else { \Froxlor\UI\Response::standard_error('loginnameiswrong', $loginname, true); } @@ -357,26 +391,6 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource \Froxlor\UI\Response::standard_error('documentrootexists', $documentroot, true); } - if ($createstdsubdomain != '1') { - $createstdsubdomain = '0'; - } - - if ($phpenabled != '0') { - $phpenabled = '1'; - } - - if ($perlenabled != '0') { - $perlenabled = '1'; - } - - if ($dnsenabled != '0') { - $dnsenabled = '1'; - } - - if ($logviewenabled != '0') { - $logviewenabled = '1'; - } - if ($password == '') { $password = \Froxlor\System\Crypt::generatePassword(); } @@ -399,6 +413,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource 'email' => $email, 'customerno' => $customernumber, 'lang' => $def_language, + 'api_allowed' => $api_allowed, 'docroot' => $documentroot, 'guid' => $guid, 'diskspace' => $diskspace, @@ -439,6 +454,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource `email` = :email, `customernumber` = :customerno, `def_language` = :lang, + `api_allowed` = :api_allowed, `documentroot` = :docroot, `guid` = :guid, `diskspace` = :diskspace, @@ -542,37 +558,14 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource Database::pexecute($ins_stmt, $ins_data, true, true); \Froxlor\System\Cronjob::inserttask('1'); - $cryptPassword = \Froxlor\System\Crypt::makeCryptPassword($password); - // add FTP-User - // @fixme use Ftp-ApiCommand later - $ins_stmt = Database::prepare(" - INSERT INTO `" . TABLE_FTP_USERS . "` SET `customerid` = :customerid, `username` = :username, `description` = :desc, - `password` = :passwd, `homedir` = :homedir, `login_enabled` = 'y', `uid` = :guid, `gid` = :guid - "); - $ins_data = array( - 'customerid' => $customerid, - 'username' => $loginname, - 'passwd' => $cryptPassword, - 'homedir' => $documentroot, - 'guid' => $guid, - 'desc' => "Default" - ); - Database::pexecute($ins_stmt, $ins_data, true, true); - // add FTP-Group - // @fixme use Ftp-ApiCommand later - $ins_stmt = Database::prepare(" - INSERT INTO `" . TABLE_FTP_GROUPS . "` SET `customerid` = :customerid, `groupname` = :groupname, `gid` = :guid, `members` = :members - "); - $ins_data = array( - 'customerid' => $customerid, - 'groupname' => $loginname, - 'guid' => $guid, - 'members' => $loginname . ',' . Settings::Get('system.httpuser') - ); + // add default FTP-User // also, add froxlor-local user to ftp-group (if exists!) to // allow access to customer-directories from within the panel, which // is necessary when pathedit = Dropdown + $local_users = array( + Settings::Get('system.httpuser') + ); if ((int) Settings::Get('system.mod_fcgid_ownvhost') == 1 || (int) Settings::Get('phpfpm.enabled_ownvhost') == 1) { if ((int) Settings::Get('system.mod_fcgid') == 1) { $local_user = Settings::Get('system.mod_fcgid_httpuser'); @@ -581,22 +574,20 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource } // check froxlor-local user membership in ftp-group // without this check addition may duplicate user in list if httpuser == local_user - if (strpos($ins_data['members'], $local_user) == false) { - $ins_data['members'] .= ',' . $local_user; + if (in_array($local_user, $local_users) == false) { + $local_users[] = $local_user; } } - Database::pexecute($ins_stmt, $ins_data, true, true); - - // FTP-Quotatallies - // @fixme use Ftp-ApiCommand later - $ins_stmt = Database::prepare(" - INSERT INTO `" . TABLE_FTP_QUOTATALLIES . "` SET `name` = :name, `quota_type` = 'user', `bytes_in_used` = '0', - `bytes_out_used` = '0', `bytes_xfer_used` = '0', `files_in_used` = '0', `files_out_used` = '0', `files_xfer_used` = '0' - "); - Database::pexecute($ins_stmt, array( - 'name' => $loginname - ), true, true); - $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] automatically added ftp-account for user '" . $loginname . "'"); + $this->apiCall('Ftps.add', array( + 'customerid' => $customerid, + 'path' => '/', + 'ftp_password' => $password, + 'ftp_description' => "Default", + 'sendinfomail' => 0, + 'ftp_username' => $loginname, + 'additional_members' => $local_users, + 'is_defaultuser' => 1 + )); $_stdsubdomain = ''; if ($createstdsubdomain == '1') { @@ -749,6 +740,8 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource * optional * @param string $def_language, * optional, default is system-default language + * @param bool $api_allowed + * optional, default is true if system setting api.enabled is true, else false * @param int $gender * optional, 0 = no-gender, 1 = male, 2 = female * @param string $custom_notes @@ -851,6 +844,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource $fax = $this->getParam('fax', true, $result['fax']); $customernumber = $this->getParam('customernumber', true, $result['customernumber']); $def_language = $this->getParam('def_language', true, $result['def_language']); + $api_allowed = $this->getBoolParam('api_allowed', true, $result['api_allowed']); $gender = (int) $this->getParam('gender', true, $result['gender']); $custom_notes = $this->getParam('custom_notes', true, $result['custom_notes']); $custom_notes_show = $this->getBoolParam('custom_notes_show', true, $result['custom_notes_show']); @@ -897,7 +891,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource $email = $idna_convert->encode(\Froxlor\Validate\Validate::validate($email, 'email', '', '', array(), true)); $customernumber = \Froxlor\Validate\Validate::validate($customernumber, 'customer number', '/^[A-Za-z0-9 \-]*$/Di', '', array(), true); $custom_notes = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $custom_notes), 'custom_notes', '/^[^\0]*$/', '', array(), true); - if (!empty($allowed_phpconfigs)) { + if (! empty($allowed_phpconfigs)) { $allowed_phpconfigs = array_map('intval', $allowed_phpconfigs); } } @@ -993,30 +987,10 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource \Froxlor\System\Cronjob::inserttask('1'); } - if ($deactivated != '1') { - $deactivated = '0'; - } - - if ($phpenabled != '0') { - $phpenabled = '1'; - } - - if ($perlenabled != '0') { - $perlenabled = '1'; - } - - if ($dnsenabled != '0') { - $dnsenabled = '1'; - } - if ($phpenabled != $result['phpenabled'] || $perlenabled != $result['perlenabled']) { \Froxlor\System\Cronjob::inserttask('1'); } - if ($logviewenabled != '0') { - $logviewenabled = '1'; - } - // activate/deactivate customer services if ($deactivated != $result['deactivated']) { @@ -1061,6 +1035,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource $dbm = new \Froxlor\Database\DbManager($this->logger()); // For each of them + $priv_changed = false; while ($row_database = $databases_stmt->fetch(\PDO::FETCH_ASSOC)) { if ($last_dbserver != $row_database['dbserver']) { @@ -1081,10 +1056,13 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource $dbm->getManager()->enableUser($row_database['databasename'], $mysql_access_host); } } + $priv_changed = true; } // At last flush the new privileges - $dbm->getManager()->flushPrivileges(); + if ($priv_changed) { + $dbm->getManager()->flushPrivileges(); + } Database::needRoot(false); // reactivate/deactivate api-keys @@ -1156,7 +1134,8 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource 'dnsenabled' => $dnsenabled, 'logviewenabled' => $logviewenabled, 'custom_notes' => $custom_notes, - 'custom_notes_show' => $custom_notes_show + 'custom_notes_show' => $custom_notes_show, + 'api_allowed' => $api_allowed ); $upd_data = $upd_data + $admin_upd_data; } @@ -1197,7 +1176,8 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource `dnsenabled` = :dnsenabled, `logviewenabled` = :logviewenabled, `custom_notes` = :custom_notes, - `custom_notes_show` = :custom_notes_show"; + `custom_notes_show` = :custom_notes_show, + `api_allowed` = :api_allowed"; $upd_query .= $admin_upd_query; } $upd_query .= " WHERE `customerid` = :customerid"; @@ -1365,6 +1345,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource $dbm = new \Froxlor\Database\DbManager($this->logger()); + $priv_changed = false; while ($row_database = $databases_stmt->fetch(\PDO::FETCH_ASSOC)) { if ($last_dbserver != $row_database['dbserver']) { Database::needRoot(true, $row_database['dbserver']); @@ -1372,8 +1353,11 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource $last_dbserver = $row_database['dbserver']; } $dbm->getManager()->deleteDatabase($row_database['databasename']); + $priv_changed = true; + } + if ($priv_changed) { + $dbm->getManager()->flushPrivileges(); } - $dbm->getManager()->flushPrivileges(); Database::needRoot(false); // delete customer itself diff --git a/lib/Froxlor/Api/Commands/DirOptions.php b/lib/Froxlor/Api/Commands/DirOptions.php index b2ec7fb4..ad5116b9 100644 --- a/lib/Froxlor/Api/Commands/DirOptions.php +++ b/lib/Froxlor/Api/Commands/DirOptions.php @@ -394,7 +394,7 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc { if ($errdoc !== null && $errdoc != '') { // not a URL - if ((strtoupper(substr($errdoc, 0, 5)) != 'HTTP:' && strtoupper(substr($errdoc, 0, 6)) != 'HTTPS:') || ! \Froxlor\Validate\Form\Data::validateUrl($errdoc)) { + if ((strtoupper(substr($errdoc, 0, 5)) != 'HTTP:' && strtoupper(substr($errdoc, 0, 6)) != 'HTTPS:') || ! \Froxlor\Validate\Validate::validateUrl($errdoc)) { // a file if (substr($errdoc, 0, 1) != '"') { $errdoc = \Froxlor\FileDir::makeCorrectFile($errdoc); diff --git a/lib/Froxlor/Api/Commands/DomainZones.php b/lib/Froxlor/Api/Commands/DomainZones.php index ccdcad79..2c94823c 100644 --- a/lib/Froxlor/Api/Commands/DomainZones.php +++ b/lib/Froxlor/Api/Commands/DomainZones.php @@ -138,6 +138,43 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour $errors[] = $this->lng['error']['dns_arec_noipv4']; } elseif ($type == 'AAAA' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { $errors[] = $this->lng['error']['dns_aaaarec_noipv6']; + } elseif ($type == 'CAA' && ! empty($content)) { + $re = '/(?\'critical\'\d)\h*(?\'type\'iodef|issue|issuewild)\h*(?\'value\'(?\'issuevalue\'"(?\'domain\'(?=.{3,128}$)(?>(?>[a-zA-Z0-9]+[a-zA-Z0-9-]*[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)*(?>[a-zA-Z]{2,}|[a-zA-Z0-9]{2,}\.[a-zA-Z]{2,}))[;\h]*(?\'parameters\'(?>[a-zA-Z0-9]{1,60}=[a-zA-Z0-9]{1,60}\h*)+)?")|(?\'iodefvalue\'"(?\'url\'(mailto:.*|http:\/\/.*|https:\/\/.*))"))/'; + preg_match($re, $content, $matches); + + if (empty($matches)) { + $errors[] = $this->lng['error']['dns_content_invalid']; + } elseif (($matches['type'] == 'issue' || $matches['type'] == 'issuewild') && ! \Froxlor\Validate\Validate::validateDomain($matches['domain'])) { + $errors[] = $this->lng['error']['dns_content_invalid']; + } elseif ($matches['type'] == 'iodef' && ! \Froxlor\Validate\Validate::validateUrl($matches['url'])) { + $errors[] = $this->lng['error']['dns_content_invalid']; + } else { + $content = $matches[0]; + } + } elseif ($type == 'CNAME' || $type == 'DNAME') { + // check for trailing dot + if (substr($content, - 1) == '.') { + // remove it for checks + $content = substr($content, 0, - 1); + } else { + // add domain name + $content .= '.' . $domain; + } + if (! \Froxlor\Validate\Validate::validateDomain($content, true)) { + $errors[] = $this->lng['error']['dns_cname_invaliddom']; + } else { + // check whether there are RR-records for the same resource + foreach ($dom_entries as $existing_entries) { + if (($existing_entries['type'] == 'A' || $existing_entries['type'] == 'AAAA' || $existing_entries['type'] == 'MX' || $existing_entries['type'] == 'NS') && $existing_entries['record'] == $record) { + $errors[] = $this->lng['error']['dns_cname_nomorerr']; + break; + } + } + } + // append trailing dot (again) + $content .= '.'; + } elseif ($type == 'LOC' && ! empty($content)) { + $content = $content; } elseif ($type == 'MX') { if ($prio === null || $prio < 0) { $errors[] = $this->lng['error']['dns_mx_prioempty']; @@ -161,28 +198,6 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour } // append trailing dot (again) $content .= '.'; - } elseif ($type == 'CNAME') { - // check for trailing dot - if (substr($content, - 1) == '.') { - // remove it for checks - $content = substr($content, 0, - 1); - } else { - // add domain name - $content .= '.' . $domain; - } - if (! \Froxlor\Validate\Validate::validateDomain($content, true)) { - $errors[] = $this->lng['error']['dns_cname_invaliddom']; - } else { - // check whether there are RR-records for the same resource - foreach ($dom_entries as $existing_entries) { - if (($existing_entries['type'] == 'A' || $existing_entries['type'] == 'AAAA' || $existing_entries['type'] == 'MX' || $existing_entries['type'] == 'NS') && $existing_entries['record'] == $record) { - $errors[] = $this->lng['error']['dns_cname_nomorerr']; - break; - } - } - } - // append trailing dot (again) - $content .= '.'; } elseif ($type == 'NS') { // check for trailing dot if (substr($content, - 1) == '.') { @@ -194,9 +209,8 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour } // append trailing dot (again) $content .= '.'; - } elseif ($type == 'TXT' && ! empty($content)) { - // check that TXT content is enclosed in " " - $content = \Froxlor\Dns\Dns::encloseTXTContent($content); + } elseif ($type == 'RP' && ! empty($content)) { + $content = $content; } elseif ($type == 'SRV') { if ($prio === null || $prio < 0) { $errors[] = $this->lng['error']['dns_srv_prioempty']; @@ -232,6 +246,11 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour if (substr($content, - 1) != '.') { $content .= '.'; } + } elseif ($type == 'SSHFP' && ! empty($content)) { + $content = $content; + } elseif ($type == 'TXT' && ! empty($content)) { + // check that TXT content is enclosed in " " + $content = \Froxlor\Dns\Dns::encloseTXTContent($content); } $new_entry = array( @@ -354,12 +373,50 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour } /** - * You cannot list dns zones. - * To get all domains use Domains.listing() or SubDomains.listing() + * List all entry records of a given domain by either id or domainname + * + * @param int $id + * optional, the domain id + * @param string $domainname + * optional, the domain name + * + * @access admin, customer + * @throws \Exception + * @return bool */ public function listing() { - throw new \Exception('You cannot list dns zones. To get all domains use Domains.listing() or SubDomains.listing()', 303); + if (Settings::Get('system.dnsenabled') != '1') { + throw new \Exception("DNS service not enabled on this system", 405); + } + + if ($this->isAdmin() == false && $this->getUserDetail('dnsenabled') != '1') { + throw new \Exception("You cannot access this resource", 405); + } + + $id = $this->getParam('id', true, 0); + $dn_optional = ($id <= 0 ? false : true); + $domainname = $this->getParam('domainname', $dn_optional, ''); + + // get requested domain + $result = $this->apiCall('SubDomains.get', array( + 'id' => $id, + 'domainname' => $domainname + )); + $id = $result['id']; + + $sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_DOMAIN_DNS . "` WHERE `domain_id` = :did"); + Database::pexecute($sel_stmt, array( + 'did' => $id + ), true, true); + $result = []; + while ($row = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) { + $result[] = $row; + } + return $this->response(200, "successfull", array( + 'count' => count($result), + 'list' => $result + )); } /** diff --git a/lib/Froxlor/Api/Commands/Domains.php b/lib/Froxlor/Api/Commands/Domains.php index 05104b25..8fb5c190 100644 --- a/lib/Froxlor/Api/Commands/Domains.php +++ b/lib/Froxlor/Api/Commands/Domains.php @@ -119,8 +119,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn * optional, default is the calling admin's ID * @param array $ipandport * optional list of ip/ports to assign to domain, default is system-default-ips - * @param bool $subcanemaildomain - * optional, allow subdomains of this domain as email domains, default 0 (false) + * @param int $subcanemaildomain + * optional, allow subdomains of this domain as email domains, 1 = choosable (default no), 2 = choosable (default yes), 3 = always, default 0 (never) * @param bool $isemaildomain * optional, allow email usage with this domain, default 0 (false) * @param bool $email_only @@ -147,6 +147,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn * optional, currently not in use, default 0 (false) * @param string $specialsettings * optional, custom webserver vhost-content which is added to the generated vhost, default empty + * @param string $ssl_specialsettings + * optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty + * @param bool $include_specialsettings + * optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false * @param bool $notryfiles * optional, [nginx only] do not generate the default try-files directive, default 0 (false) * @param bool $writeaccesslog @@ -170,7 +174,9 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn * @param bool $letsencrypt * optional, whether to generate a Let's Encrypt certificate for this domain, default false; requires SSL to be enabled * @param array $ssl_ipandport - * optional, list of ssl-enabled ip/port id's to assign to this domain + * optional, list of ssl-enabled ip/port id's to assign to this domain, default empty + * @param bool $dont_use_default_ssl_ipandport_if_empty + * optional, do NOT set the systems default ssl ip addresses if none are given via $ssl_ipandport parameter * @param bool $http2 * optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default 0 (false) * @param int $hsts_maxage @@ -181,6 +187,14 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn * optional whether or not to preload HSTS header value * @param bool $ocsp_stapling * optional whether to enable ocsp-stapling for this domain. default 0 (false), requires SSL + * @param bool $override_tls + * optional whether or not to override system-tls settings like protocol, ssl-ciphers and if applicable tls-1.3 ciphers, requires change_serversettings flag for the admin, default false + * @param array $ssl_protocols + * optional list of allowed/used ssl/tls protocols, see system.ssl_protocols setting, only used/required if $override_tls is true, default empty or system.ssl_protocols setting if $override_tls is true + * @param string $ssl_cipher_list + * optional list of allowed/used ssl/tls ciphers, see system.ssl_cipher_list setting, only used/required if $override_tls is true, default empty or system.ssl_cipher_list setting if $override_tls is true + * @param string $tlsv13_cipher_list + * optional list of allowed/used tls-1.3 specific ciphers, see system.tlsv13_cipher_list setting, only used/required if $override_tls is true, default empty or system.tlsv13_cipher_list setting if $override_tls is true * * @access admin * @throws \Exception @@ -212,6 +226,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $zonefile = $this->getParam('zonefile', true, ''); $dkim = $this->getBoolParam('dkim', true, 0); $specialsettings = $this->getParam('specialsettings', true, ''); + $ssl_specialsettings = $this->getParam('ssl_specialsettings', true, ''); + $include_specialsettings = $this->getBoolParam('include_specialsettings', true, 0); $notryfiles = $this->getBoolParam('notryfiles', true, 0); $writeaccesslog = $this->getBoolParam('writeaccesslog', true, 1); $writeerrorlog = $this->getBoolParam('writeerrorlog', true, 1); @@ -223,13 +239,27 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, - 1); $ssl_redirect = $this->getBoolParam('ssl_redirect', true, 0); $letsencrypt = $this->getBoolParam('letsencrypt', true, 0); - $p_ssl_ipandports = $this->getParam('ssl_ipandport', true, explode(',', Settings::Get('system.defaultsslip'))); + $dont_use_default_ssl_ipandport_if_empty = $this->getBoolParam('dont_use_default_ssl_ipandport_if_empty', true, 0); + $p_ssl_ipandports = $this->getParam('ssl_ipandport', true, $dont_use_default_ssl_ipandport_if_empty ? array() : explode(',', Settings::Get('system.defaultsslip'))); $http2 = $this->getBoolParam('http2', true, 0); $hsts_maxage = $this->getParam('hsts_maxage', true, 0); $hsts_sub = $this->getBoolParam('hsts_sub', true, 0); $hsts_preload = $this->getBoolParam('hsts_preload', true, 0); $ocsp_stapling = $this->getBoolParam('ocsp_stapling', true, 0); + $override_tls = $this->getBoolParam('override_tls', true, 0); + $p_ssl_protocols = array(); + $ssl_cipher_list = ""; + $tlsv13_cipher_list = ""; + + if ($this->getUserDetail('change_serversettings') == '1') { + if ($override_tls) { + $p_ssl_protocols = $this->getParam('ssl_protocols', true, explode(',', Settings::Get('system.ssl_protocols'))); + $ssl_cipher_list = $this->getParam('ssl_cipher_list', true, Settings::Get('system.ssl_cipher_list')); + $tlsv13_cipher_list = $this->getParam('tlsv13_cipher_list', true, Settings::Get('system.tlsv13_cipher_list')); + } + } + // validation if ($p_domain == Settings::Get('system.hostname')) { \Froxlor\UI\Response::standard_error('admin_domain_emailsystemhostname', '', true); @@ -283,7 +313,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn '0', '' ), true); - if ($registration_date == '0000-00-00') { + if ($registration_date == '0000-00-00' || empty($registration_date)) { $registration_date = null; } @@ -292,7 +322,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn '0', '' ), true); - if ($termination_date == '0000-00-00') { + if ($termination_date == '0000-00-00' || empty($termination_date)) { $termination_date = null; } @@ -316,6 +346,34 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn } else { $documentroot = $_documentroot; } + + $ssl_protocols = array(); + if (! empty($p_ssl_protocols) && is_numeric($p_ssl_protocols)) { + $p_ssl_protocols = array( + $p_ssl_protocols + ); + } + if (! empty($p_ssl_protocols) && ! is_array($p_ssl_protocols)) { + $p_ssl_protocols = json_decode($p_ssl_protocols, true); + } + if (! empty($p_ssl_protocols) && is_array($p_ssl_protocols)) { + $protocols_available = array( + 'TLSv1', + 'TLSv1.1', + 'TLSv1.2', + 'TLSv1.3' + ); + foreach ($p_ssl_protocols as $ssl_protocol) { + if (! in_array(trim($ssl_protocol), $protocols_available)) { + $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_DEBUG, "[API] unknown SSL protocol '" . trim($ssl_protocol) . "'"); + continue; + } + $ssl_protocols[] = $ssl_protocol; + } + } + if (empty($ssl_protocols)) { + $override_tls = '0'; + } } else { $isbinddomain = '0'; if (Settings::Get('system.bind_enable') == '1') { @@ -325,10 +383,14 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $zonefile = ''; $dkim = '0'; $specialsettings = ''; + $ssl_specialsettings = ''; + $include_specialsettings = 0; $notryfiles = '0'; $writeaccesslog = '1'; $writeerrorlog = '1'; $documentroot = $_documentroot; + $override_tls = '0'; + $ssl_protocols = array(); } if ($this->getUserDetail('caneditphpsettings') == '1' || $this->getUserDetail('change_serversettings') == '1') { @@ -388,6 +450,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $ssl_ipandports = array(); if (Settings::Get('system.use_ssl') == "1" && ! empty($p_ssl_ipandports)) { $ssl_ipandports = $this->validateIpAddresses($p_ssl_ipandports, true); + + if ($this->getUserDetail('change_serversettings') == '1') { + $ssl_specialsettings = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $ssl_specialsettings), 'ssl_specialsettings', '/^[^\0]*$/', '', array(), true); + } } if (Settings::Get('system.use_ssl') == "0" || empty($ssl_ipandports)) { $ssl_redirect = 0; @@ -404,17 +470,16 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn // OCSP stapling $ocsp_stapling = 0; + + // vhost container settings + $ssl_specialsettings = ''; + $include_specialsettings = 0; } - // We can't enable let's encrypt for wildcard - domains if using acme-v1 - if ($serveraliasoption == '0' && $letsencrypt == '1' && Settings::Get('system.leapiversion') == '1') { + // We can't enable let's encrypt for wildcard-domains + if ($serveraliasoption == '0' && $letsencrypt == '1') { \Froxlor\UI\Response::standard_error('nowildcardwithletsencrypt', '', true); } - // if using acme-v2 we cannot issue wildcard-certificates - // because they currently only support the dns-01 challenge - if ($serveraliasoption == '0' && $letsencrypt == '1' && Settings::Get('system.leapiversion') == '2') { - \Froxlor\UI\Response::standard_error('nowildcardwithletsencryptv2', '', true); - } // Temporarily deactivate ssl_redirect until Let's Encrypt certificate was generated if ($ssl_redirect > 0 && $letsencrypt == 1) { @@ -542,6 +607,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn 'openbasedir' => $openbasedir, 'speciallogfile' => $speciallogfile, 'specialsettings' => $specialsettings, + 'ssl_specialsettings' => $ssl_specialsettings, + 'include_specialsettings' => $include_specialsettings, 'notryfiles' => $notryfiles, 'writeaccesslog' => $writeaccesslog, 'writeerrorlog' => $writeerrorlog, @@ -558,7 +625,11 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn 'hsts' => $hsts_maxage, 'hsts_sub' => $hsts_sub, 'hsts_preload' => $hsts_preload, - 'ocsp_stapling' => $ocsp_stapling + 'ocsp_stapling' => $ocsp_stapling, + 'override_tls' => $override_tls, + 'ssl_protocols' => implode(",", $ssl_protocols), + 'ssl_cipher_list' => $ssl_cipher_list, + 'tlsv13_cipher_list' => $tlsv13_cipher_list ); $ins_stmt = Database::prepare(" @@ -584,6 +655,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn `openbasedir` = :openbasedir, `speciallogfile` = :speciallogfile, `specialsettings` = :specialsettings, + `ssl_specialsettings` = :ssl_specialsettings, + `include_specialsettings` = :include_specialsettings, `notryfiles` = :notryfiles, `writeaccesslog` = :writeaccesslog, `writeerrorlog` = :writeerrorlog, @@ -600,7 +673,11 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn `hsts` = :hsts, `hsts_sub` = :hsts_sub, `hsts_preload` = :hsts_preload, - `ocsp_stapling` = :ocsp_stapling + `ocsp_stapling` = :ocsp_stapling, + `override_tls` = :override_tls, + `ssl_protocols` = :ssl_protocols, + `ssl_cipher_list` = :ssl_cipher_list, + `tlsv13_cipher_list` = :tlsv13_cipher_list "); Database::pexecute($ins_stmt, $ins_data, true, true); $domainid = Database::lastInsertId(); @@ -670,8 +747,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn * optional, default is the calling admin's ID * @param array $ipandport * optional list of ip/ports to assign to domain, default is system-default-ips - * @param bool $subcanemaildomain - * optional, allow subdomains of this domain as email domains, default 0 (false) + * @param int $subcanemaildomain + * optional, allow subdomains of this domain as email domains, 1 = choosable (default no), 2 = choosable (default yes), 3 = always, default 0 (never) * @param bool $isemaildomain * optional, allow email usage with this domain, default 0 (false) * @param bool $email_only @@ -700,6 +777,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn * optional, currently not in use, default 0 (false) * @param string $specialsettings * optional, custom webserver vhost-content which is added to the generated vhost, default empty + * @param string $ssl_specialsettings + * optional, custom webserver vhost-content which is added to the generated ssl-vhost, default empty + * @param bool $include_specialsettings + * optional, whether or not to include non-ssl specialsettings in the generated ssl-vhost, default false * @param bool $specialsettingsforsubdomains * optional, whether to apply specialsettings to all subdomains of this domain, default 0 (false) * @param bool $notryfiles @@ -764,7 +845,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $customerid = intval($this->getParam('customerid', true, $result['customerid'])); $adminid = intval($this->getParam('adminid', true, $result['adminid'])); - $subcanemaildomain = $this->getBoolParam('subcanemaildomain', true, $result['subcanemaildomain']); + $subcanemaildomain = $this->getParam('subcanemaildomain', true, $result['subcanemaildomain']); $isemaildomain = $this->getBoolParam('isemaildomain', true, $result['isemaildomain']); $email_only = $this->getBoolParam('email_only', true, $result['email_only']); $p_serveraliasoption = $this->getParam('selectserveralias', true, - 1); @@ -779,6 +860,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $zonefile = $this->getParam('zonefile', true, $result['zonefile']); $dkim = $this->getBoolParam('dkim', true, $result['dkim']); $specialsettings = $this->getParam('specialsettings', true, $result['specialsettings']); + $ssl_specialsettings = $this->getParam('ssl_specialsettings', true, $result['ssl_specialsettings']); + $include_specialsettings = $this->getBoolParam('include_specialsettings', true, $result['include_specialsettings']); $ssfs = $this->getBoolParam('specialsettingsforsubdomains', true, 0); $notryfiles = $this->getBoolParam('notryfiles', true, $result['notryfiles']); $writeaccesslog = $this->getBoolParam('writeaccesslog', true, $result['writeaccesslog']); @@ -799,6 +882,24 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $hsts_preload = $this->getBoolParam('hsts_preload', true, $result['hsts_preload']); $ocsp_stapling = $this->getBoolParam('ocsp_stapling', true, $result['ocsp_stapling']); + $override_tls = $this->getBoolParam('override_tls', true, $result['override_tls']); + + if ($this->getUserDetail('change_serversettings') == '1') { + if ($override_tls) { + $p_ssl_protocols = $this->getParam('ssl_protocols', true, explode(',', $result['ssl_protocols'])); + $ssl_cipher_list = $this->getParam('ssl_cipher_list', true, $result['ssl_cipher_list']); + $tlsv13_cipher_list = $this->getParam('tlsv13_cipher_list', true, $result['tlsv13_cipher_list']); + } else { + $p_ssl_protocols = array(); + $ssl_cipher_list = ""; + $tlsv13_cipher_list = ""; + } + } else { + $p_ssl_protocols = explode(',', $result['ssl_protocols']); + $ssl_cipher_list = $result['ssl_cipher_list']; + $tlsv13_cipher_list = $result['tlsv13_cipher_list']; + } + // count subdomain usage of source-domain $subdomains_stmt = Database::prepare(" SELECT COUNT(`id`) AS count FROM `" . TABLE_PANEL_DOMAINS . "` WHERE @@ -905,7 +1006,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn '0', '' ), true); - if ($registration_date == '0000-00-00') { + if ($registration_date == '0000-00-00' || empty($registration_date)) { $registration_date = null; } $termination_date = \Froxlor\Validate\Validate::validate($termination_date, 'termination_date', '/^(19|20)\d\d[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])$/', '', array( @@ -913,7 +1014,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn '0', '' ), true); - if ($termination_date == '0000-00-00') { + if ($termination_date == '0000-00-00' || empty($termination_date)) { $termination_date = null; } @@ -968,16 +1069,48 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn if (! preg_match('/^https?\:\/\//', $documentroot) && strstr($documentroot, ":") !== false) { \Froxlor\UI\Response::standard_error('pathmaynotcontaincolon', '', true); } + + $ssl_protocols = array(); + if (! empty($p_ssl_protocols) && is_numeric($p_ssl_protocols)) { + $p_ssl_protocols = array( + $p_ssl_protocols + ); + } + if (! empty($p_ssl_protocols) && ! is_array($p_ssl_protocols)) { + $p_ssl_protocols = json_decode($p_ssl_protocols, true); + } + if (! empty($p_ssl_protocols) && is_array($p_ssl_protocols)) { + $protocols_available = array( + 'TLSv1', + 'TLSv1.1', + 'TLSv1.2', + 'TLSv1.3' + ); + foreach ($p_ssl_protocols as $ssl_protocol) { + if (! in_array(trim($ssl_protocol), $protocols_available)) { + $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_DEBUG, "[API] unknown SSL protocol '" . trim($ssl_protocol) . "'"); + continue; + } + $ssl_protocols[] = $ssl_protocol; + } + } + if (empty($ssl_protocols)) { + $override_tls = '0'; + } } else { $isbinddomain = $result['isbinddomain']; $zonefile = $result['zonefile']; $dkim = $result['dkim']; $specialsettings = $result['specialsettings']; + $ssl_specialsettings = $result['ssl_specialsettings']; + $include_specialsettings = $result['include_specialsettings']; $ssfs = (empty($specialsettings) ? 0 : 1); $notryfiles = $result['notryfiles']; $writeaccesslog = $result['writeaccesslog']; $writeerrorlog = $result['writeerrorlog']; $documentroot = $result['documentroot']; + + $override_tls = $result['override_tls']; } if ($this->getUserDetail('caneditphpsettings') == '1' || $this->getUserDetail('change_serversettings') == '1') { @@ -1028,6 +1161,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $ssl_ipandports = array(); if (Settings::Get('system.use_ssl') == "1" && ! empty($p_ssl_ipandports)) { $ssl_ipandports = $this->validateIpAddresses($p_ssl_ipandports, true, $result['id']); + + if ($this->getUserDetail('change_serversettings') == '1') { + $ssl_specialsettings = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $ssl_specialsettings), 'ssl_specialsettings', '/^[^\0]*$/', '', array(), true); + } } if (Settings::Get('system.use_ssl') == "0" || empty($ssl_ipandports)) { $ssl_redirect = 0; @@ -1044,17 +1181,16 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn // OCSP stapling $ocsp_stapling = 0; + + // vhost container settings + $ssl_specialsettings = ''; + $include_specialsettings = 0; } - // We can't enable let's encrypt for wildcard domains when using acme-v1 - if ($serveraliasoption == '0' && $letsencrypt == '1' && Settings::Get('system.leapiversion') == '1') { + // We can't enable let's encrypt for wildcard-domains + if ($serveraliasoption == '0' && $letsencrypt == '1') { \Froxlor\UI\Response::standard_error('nowildcardwithletsencrypt', '', true); } - // if using acme-v2 we cannot issue wildcard-certificates - // because they currently only support the dns-01 challenge - if ($serveraliasoption == '0' && $letsencrypt == '1' && Settings::Get('system.leapiversion') == '2') { - \Froxlor\UI\Response::standard_error('nowildcardwithletsencryptv2', '', true); - } // Temporarily deactivate ssl_redirect until Let's Encrypt certificate was generated if ($ssl_redirect > 0 && $letsencrypt == 1 && $result['letsencrypt'] != $letsencrypt) { @@ -1252,12 +1388,16 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn if ($ssfs == 1) { $_update_data['specialsettings'] = $specialsettings; - $upd_specialsettings = ", `specialsettings` = :specialsettings "; + $_update_data['ssl_specialsettings'] = $ssl_specialsettings; + $_update_data['include_specialsettings'] = $include_specialsettings; + $upd_specialsettings = ", `specialsettings` = :specialsettings, `ssl_specialsettings` = :ssl_specialsettings, `include_specialsettings` = :include_specialsettings "; } else { $upd_specialsettings = ''; unset($_update_data['specialsettings']); + unset($_update_data['ssl_specialsettings']); + unset($_update_data['include_specialsettings']); $upd_stmt = Database::prepare(" - UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `specialsettings`='' WHERE `parentdomainid` = :id + UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `specialsettings`='', `ssl_specialsettings`='', `include_specialsettings`='0' WHERE `parentdomainid` = :id "); Database::pexecute($upd_stmt, array( 'id' => $id @@ -1290,6 +1430,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $update_data['mod_fcgid_starter'] = $mod_fcgid_starter; $update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests; $update_data['specialsettings'] = $specialsettings; + $update_data['ssl_specialsettings'] = $ssl_specialsettings; + $update_data['include_specialsettings'] = $include_specialsettings; $update_data['notryfiles'] = $notryfiles; $update_data['writeaccesslog'] = $writeaccesslog; $update_data['writeerrorlog'] = $writeerrorlog; @@ -1302,6 +1444,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $update_data['hsts_sub'] = $hsts_sub; $update_data['hsts_preload'] = $hsts_preload; $update_data['ocsp_stapling'] = $ocsp_stapling; + $update_data['override_tls'] = $override_tls; + $update_data['ssl_protocols'] = implode(",", $ssl_protocols); + $update_data['ssl_cipher_list'] = $ssl_cipher_list; + $update_data['tlsv13_cipher_list'] = $tlsv13_cipher_list; $update_data['id'] = $id; $update_stmt = Database::prepare(" @@ -1327,6 +1473,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn `mod_fcgid_starter` = :mod_fcgid_starter, `mod_fcgid_maxrequests` = :mod_fcgid_maxrequests, `specialsettings` = :specialsettings, + `ssl_specialsettings` = :ssl_specialsettings, + `include_specialsettings` = :include_specialsettings, `notryfiles` = :notryfiles, `writeaccesslog` = :writeaccesslog, `writeerrorlog` = :writeerrorlog, @@ -1338,7 +1486,11 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn `hsts` = :hsts, `hsts_sub` = :hsts_sub, `hsts_preload` = :hsts_preload, - `ocsp_stapling` = :ocsp_stapling + `ocsp_stapling` = :ocsp_stapling, + `override_tls` = :override_tls, + `ssl_protocols` = :ssl_protocols, + `ssl_cipher_list` = :ssl_cipher_list, + `tlsv13_cipher_list` = :tlsv13_cipher_list WHERE `id` = :id "); Database::pexecute($update_stmt, $update_data, true, true); @@ -1349,6 +1501,10 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn $_update_data['openbasedir'] = $openbasedir; $_update_data['mod_fcgid_starter'] = $mod_fcgid_starter; $_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests; + $_update_data['override_tls'] = $override_tls; + $_update_data['ssl_protocols'] = implode(",", $ssl_protocols); + $_update_data['ssl_cipher_list'] = $ssl_cipher_list; + $_update_data['tlsv13_cipher_list'] = $tlsv13_cipher_list; $_update_data['parentdomainid'] = $id; // if php config is to be set for all subdomains, check here @@ -1373,7 +1529,11 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn `phpenabled` = :phpenabled, `openbasedir` = :openbasedir, `mod_fcgid_starter` = :mod_fcgid_starter, - `mod_fcgid_maxrequests` = :mod_fcgid_maxrequests + `mod_fcgid_maxrequests` = :mod_fcgid_maxrequests, + `override_tls` = :override_tls, + `ssl_protocols` = :ssl_protocols, + `ssl_cipher_list` = :ssl_cipher_list, + `tlsv13_cipher_list` = :tlsv13_cipher_list " . $update_phpconfig . $upd_specialsettings . $updatechildren . $update_sslredirect . " WHERE `parentdomainid` = :parentdomainid "); @@ -1447,14 +1607,15 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn } } } - if ($result['aliasdomain'] != $aliasdomain) { + if ($result['aliasdomain'] != $aliasdomain && is_numeric($result['aliasdomain'])) { // trigger when domain id for alias destination has changed: both for old and new destination \Froxlor\Domain\Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger()); \Froxlor\Domain\Domain::triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $this->logger()); - } elseif ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) { + } + if ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) { // or when wwwserveralias or letsencrypt was changed \Froxlor\Domain\Domain::triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $this->logger()); - if ($aliasdomain === 0) { + if ((int) $aliasdomain === 0) { // in case the wwwserveralias is set on a main domain, $aliasdomain is 0 // --> the call just above to triggerLetsEncryptCSRForAliasDestinationDomain // is a noop...let's repeat it with the domain id of the main domain @@ -1462,7 +1623,8 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn } } - $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated domain '" . $result['domain'] . "'"); + $idna_convert = new \Froxlor\Idna\IdnaWrapper(); + $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated domain '" . $idna_convert->decode($result['domain']) . "'"); return $this->response(200, "successfull", $update_data); } throw new \Exception("Not allowed to execute given command.", 403); @@ -1616,6 +1778,9 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn // remove domains DNS from powerDNS if used, #581 \Froxlor\System\Cronjob::inserttask('11', $result['domain']); + // remove domain from acme.sh / lets encrypt if used + \Froxlor\System\Cronjob::inserttask('12', $result['domain']); + $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] deleted domain/subdomains (#" . $result['id'] . ")"); \Froxlor\User::updateCounters(); \Froxlor\System\Cronjob::inserttask('1'); @@ -1633,7 +1798,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn * @param boolean $ssl * default false * @param int $edit_id - * default 0 + * default 0 * * @throws \Exception * @return array diff --git a/lib/Froxlor/Api/Commands/EmailAccounts.php b/lib/Froxlor/Api/Commands/EmailAccounts.php index 9a5f3492..98f52b3c 100644 --- a/lib/Froxlor/Api/Commands/EmailAccounts.php +++ b/lib/Froxlor/Api/Commands/EmailAccounts.php @@ -81,9 +81,9 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso )); $id = $result['id']; - $email_full = $result['email_full']; $idna_convert = new \Froxlor\Idna\IdnaWrapper(); - $username = $idna_convert->decode($email_full); + $email_full = $result['email_full']; + $username = $email_full; $password = \Froxlor\Validate\Validate::validate($email_password, 'password', '', '', array(), true); $password = \Froxlor\System\Crypt::validatePassword($password, true); diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php index ef26a57e..f4cb959a 100644 --- a/lib/Froxlor/Api/Commands/Emails.php +++ b/lib/Froxlor/Api/Commands/Emails.php @@ -340,26 +340,12 @@ class Emails extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt } // check whether this address is an account if ($result['popaccountid'] != 0) { - // Free the Quota used by the email account - if (Settings::Get('system.mail_quota_enabled') == 1) { - $stmt = Database::prepare("SELECT `quota` FROM `" . TABLE_MAIL_USERS . "` WHERE `customerid`= :customerid AND `id`= :id"); - $res_quota = Database::pexecute_first($stmt, array( - "customerid" => $customer['customerid'], - "id" => $result['popaccountid'] - ), true, true); - Customers::decreaseUsage($customer['customerid'], 'email_quota_used', '', $res_quota['quota']); - Admins::decreaseUsage($customer['customerid'], 'email_quota_used', '', $res_quota['quota']); - $this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted quota entries for email address '" . $result['email_full'] . "'"); - } - // delete account - $stmt = Database::prepare("DELETE FROM `" . TABLE_MAIL_USERS . "` WHERE `customerid`= :customerid AND `id`= :id"); - Database::pexecute($stmt, array( - "customerid" => $customer['customerid'], - "id" => $result['popaccountid'] - ), true, true); - Customers::decreaseUsage($customer['customerid'], 'email_accounts_used'); - Admins::decreaseUsage($customer['customerid'], 'email_accounts_used'); - $this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted email account '" . $result['email_full'] . "'"); + // use EmailAccounts.delete + $this->apiCall('EmailAccounts.delete', array( + 'id' => $result['id'], + 'customerid' => $customer['customerid'], + 'delete_userfiles' => $delete_userfiles + )); $number_forwarders --; } diff --git a/lib/Froxlor/Api/Commands/Froxlor.php b/lib/Froxlor/Api/Commands/Froxlor.php index 1e427240..85bf5500 100644 --- a/lib/Froxlor/Api/Commands/Froxlor.php +++ b/lib/Froxlor/Api/Commands/Froxlor.php @@ -39,7 +39,11 @@ class Froxlor extends \Froxlor\Api\ApiCommand $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] checking for updates"); // check for new version - $latestversion = \Froxlor\Http\HttpClient::urlGet(UPDATE_URI); + try { + $latestversion = \Froxlor\Http\HttpClient::urlGet(UPDATE_URI, true, 3); + } catch (\Exception $e) { + $latestversion = \Froxlor\Froxlor::getVersion()."|Version-check currently unavailable, please try again later"; + } $latestversion = explode('|', $latestversion); if (is_array($latestversion) && count($latestversion) >= 1) { diff --git a/lib/Froxlor/Api/Commands/Ftps.php b/lib/Froxlor/Api/Commands/Ftps.php index 31f949d0..68f1acad 100644 --- a/lib/Froxlor/Api/Commands/Ftps.php +++ b/lib/Froxlor/Api/Commands/Ftps.php @@ -41,6 +41,10 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit * optional if customer.ftpatdomain is allowed, specify a domain (customer must be owner) * @param int $customerid * required when called as admin, not needed when called as customer + * @param array $additional_members + * optional whether to add additional usernames to the group + * @param bool $is_defaultuser + * optional whether this is the standard default ftp user which is being added so no usage is decreased * * @access admin, customer * @throws \Exception @@ -66,6 +70,9 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit $ftpusername = $this->getParam('ftp_username', true, ''); $ftpdomain = $this->getParam('ftp_domain', true, ''); + $additional_members = $this->getParam('additional_members', true, array()); + $is_defaultuser = $this->getBoolParam('is_defaultuser', true, 0); + // validation $password = \Froxlor\Validate\Validate::validate($password, 'password', '', '', array(), true); $password = \Froxlor\System\Crypt::validatePassword($password, true); @@ -87,13 +94,18 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit $params = array(); // get needed customer info to reduce the ftp-user-counter by one - $customer = $this->getCustomerData('ftps'); + if ($is_defaultuser) { + // no resource check for default user + $customer = $this->getCustomerData(); + } else { + $customer = $this->getCustomerData('ftps'); + } if ($sendinfomail != 1) { $sendinfomail = 0; } - if (Settings::Get('customer.ftpatdomain') == '1') { + if (Settings::Get('customer.ftpatdomain') == '1' && !$is_defaultuser) { if ($ftpusername == '') { \Froxlor\UI\Response::standard_error(array( 'stringisempty', @@ -113,7 +125,11 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit } $username = $ftpusername . "@" . $ftpdomain; } else { - $username = $customer['loginname'] . Settings::Get('customer.ftpprefix') . (intval($customer['ftp_lastaccountnumber']) + 1); + if ($is_defaultuser) { + $username = $customer['loginname']; + } else { + $username = $customer['loginname'] . Settings::Get('customer.ftpprefix') . (intval($customer['ftp_lastaccountnumber']) + 1); + } } $username_check_stmt = Database::prepare(" @@ -163,7 +179,7 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit ), true, true); } - $stmt = Database::prepare(" + $group_upd_stmt = Database::prepare(" UPDATE `" . TABLE_FTP_GROUPS . "` SET `members` = CONCAT_WS(',',`members`, :username) WHERE `customerid`= :customerid AND `gid`= :guid @@ -173,12 +189,35 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit "customerid" => $customer['customerid'], "guid" => $customer['guid'] ); - Database::pexecute($stmt, $params, true, true); - // update customer usage - Customers::increaseUsage($customer['customerid'], 'ftps_used'); - Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber'); + if ($is_defaultuser) { + // add the new group + $group_ins_stmt = Database::prepare(" + INSERT INTO `" . TABLE_FTP_GROUPS . "` + SET `customerid`= :customerid, `gid`= :guid, `groupname` = :username, `members` = :username + "); + Database::pexecute($group_ins_stmt, $params, true, true); + } else { + // just update + Database::pexecute($group_upd_stmt, $params, true, true); + } + if (count($additional_members) > 0) { + foreach ($additional_members as $add_member) { + $params = array( + "username" => $add_member, + "customerid" => $customer['customerid'], + "guid" => $customer['guid'] + ); + Database::pexecute($group_upd_stmt, $params, true, true); + } + } + + if (! $is_defaultuser) { + // update customer usage + Customers::increaseUsage($customer['customerid'], 'ftps_used'); + Customers::increaseUsage($customer['customerid'], 'ftp_lastaccountnumber'); + } $this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ftp-account '" . $username . " (" . $path . ")'"); \Froxlor\System\Cronjob::inserttask(5); @@ -502,6 +541,9 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit "username" => $customer_data['loginname'] ); Database::pexecute($stmt, $params, true, true); + } else { + // do not allow removing default ftp-account + \Froxlor\UI\Response::standard_error('ftp_cantdeletemainaccount', '', true); } // remove all quotatallies diff --git a/lib/Froxlor/Api/Commands/HostingPlans.php b/lib/Froxlor/Api/Commands/HostingPlans.php index 60b275f3..b20db944 100644 --- a/lib/Froxlor/Api/Commands/HostingPlans.php +++ b/lib/Froxlor/Api/Commands/HostingPlans.php @@ -1,6 +1,9 @@ isAdmin()) { + $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list hosting-plans"); + $result_stmt = Database::prepare(" + SELECT p.*, a.loginname as adminname + FROM `" . TABLE_PANEL_PLANS . "` p, `" . TABLE_PANEL_ADMINS . "` a + WHERE `p`.`adminid` = `a`.`adminid`" . ($this->getUserDetail('customers_see_all') ? '' : " AND `p`.`adminid` = :adminid ")); + $params = array(); + if ($this->getUserDetail('customers_see_all') == '0') { + $params['adminid'] = $this->getUserDetail('adminid'); + } + Database::pexecute($result_stmt, $params); + $result = array(); + while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) { + $result[] = $row; + } + return $this->response(200, "successfull", array( + 'count' => count($result), + 'list' => $result + )); + } + throw new \Exception("Not allowed to execute given command.", 403); } + /** + * return a hosting-plan entry by either id or plan-name + * + * @param int $id + * optional, the hosting-plan-id + * @param string $planname + * optional, the hosting-plan-name + * + * @access admin + * @throws \Exception + * @return string json-encoded array + */ + public function get() + { + if ($this->isAdmin()) { + $id = $this->getParam('id', true, 0); + $dn_optional = ($id <= 0 ? false : true); + $planname = $this->getParam('planname', $dn_optional, ''); + $result_stmt = Database::prepare(" + SELECT * FROM `" . TABLE_PANEL_PLANS . "` WHERE " . ($id > 0 ? "`id` = :iddn" : "`name` = :iddn") . ($this->getUserDetail('customers_see_all') ? '' : " AND `adminid` = :adminid")); + $params = array( + 'iddn' => ($id <= 0 ? $planname : $id) + ); + if ($this->getUserDetail('customers_see_all') == '0') { + $params['adminid'] = $this->getUserDetail('adminid'); + } + $result = Database::pexecute_first($result_stmt, $params, true, true); + if ($result) { + $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] get hosting-plan '" . $result['name'] . "'"); + return $this->response(200, "successfull", $result); + } + $key = ($id > 0 ? "id #" . $id : "planname '" . $planname . "'"); + throw new \Exception("Hosting-plan with " . $key . " could not be found", 404); + } + throw new \Exception("Not allowed to execute given command.", 403); + } + + /** + * add new hosting-plan + * + * @param string $name + * name of the plan + * @param string $description + * optional, description for hosting-plan + * @param int $diskspace + * optional disk-space available for customer in MB, default 0 + * @param bool $diskspace_ul + * optional, whether customer should have unlimited diskspace, default 0 (false) + * @param int $traffic + * optional traffic available for customer in GB, default 0 + * @param bool $traffic_ul + * optional, whether customer should have unlimited traffic, default 0 (false) + * @param int $subdomains + * optional amount of subdomains available for customer, default 0 + * @param bool $subdomains_ul + * optional, whether customer should have unlimited subdomains, default 0 (false) + * @param int $emails + * optional amount of emails available for customer, default 0 + * @param bool $emails_ul + * optional, whether customer should have unlimited emails, default 0 (false) + * @param int $email_accounts + * optional amount of email-accounts available for customer, default 0 + * @param bool $email_accounts_ul + * optional, whether customer should have unlimited email-accounts, default 0 (false) + * @param int $email_forwarders + * optional amount of email-forwarders available for customer, default 0 + * @param bool $email_forwarders_ul + * optional, whether customer should have unlimited email-forwarders, default 0 (false) + * @param int $email_quota + * optional size of email-quota available for customer in MB, default is system-setting mail_quota + * @param bool $email_quota_ul + * optional, whether customer should have unlimited email-quota, default 0 (false) + * @param bool $email_imap + * optional, whether to allow IMAP access, default 0 (false) + * @param bool $email_pop3 + * optional, whether to allow POP3 access, default 0 (false) + * @param int $ftps + * optional amount of ftp-accounts available for customer, default 0 + * @param bool $ftps_ul + * optional, whether customer should have unlimited ftp-accounts, default 0 (false) + * @param int $mysqls + * optional amount of mysql-databases available for customer, default 0 + * @param bool $mysqls_ul + * optional, whether customer should have unlimited mysql-databases, default 0 (false) + * @param bool $phpenabled + * optional, whether to allow usage of PHP, default 0 (false) + * @param array $allowed_phpconfigs + * optional, array of IDs of php-config that the customer is allowed to use, default empty (none) + * @param bool $perlenabled + * optional, whether to allow usage of Perl/CGI, default 0 (false) + * @param bool $dnsenabled + * optional, ether to allow usage of the DNS editor (requires activated nameserver in settings), default 0 (false) + * @param bool $logviewenabled + * optional, ether to allow acccess to webserver access/error-logs, default 0 (false) + * + * @access admin + * @throws \Exception + * @return string json-encoded array + */ + public function add() + { + if ($this->isAdmin()) { + $name = $this->getParam('name'); + $description = $this->getParam('description', true, ''); + + $value_arr = array(); + $value_arr['diskspace'] = $this->getUlParam('diskspace', 'diskspace_ul', true, 0); + $value_arr['traffic'] = $this->getUlParam('traffic', 'traffic_ul', true, 0); + $value_arr['subdomains'] = $this->getUlParam('subdomains', 'subdomains_ul', true, 0); + $value_arr['emails'] = $this->getUlParam('emails', 'emails_ul', true, 0); + $value_arr['email_accounts'] = $this->getUlParam('email_accounts', 'email_accounts_ul', true, 0); + $value_arr['email_forwarders'] = $this->getUlParam('email_forwarders', 'email_forwarders_ul', true, 0); + $value_arr['email_quota'] = $this->getUlParam('email_quota', 'email_quota_ul', true, Settings::Get('system.mail_quota')); + $value_arr['email_imap'] = $this->getBoolParam('email_imap', true, 0); + $value_arr['email_pop3'] = $this->getBoolParam('email_pop3', true, 0); + $value_arr['ftps'] = $this->getUlParam('ftps', 'ftps_ul', true, 0); + $value_arr['mysqls'] = $this->getUlParam('mysqls', 'mysqls_ul', true, 0); + $value_arr['phpenabled'] = $this->getBoolParam('phpenabled', true, 0); + $p_allowed_phpconfigs = $this->getParam('allowed_phpconfigs', true, array()); + $value_arr['perlenabled'] = $this->getBoolParam('perlenabled', true, 0); + $value_arr['dnsenabled'] = $this->getBoolParam('dnsenabled', true, 0); + $value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, 0); + + // validation + $name = \Froxlor\Validate\Validate::validate(trim($name), 'name', '', '', array(), true); + $description = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $description), 'description', '/^[^\0]*$/'); + + if (Settings::Get('system.mail_quota_enabled') != '1') { + $value_arr['email_quota'] = - 1; + } + + $value_arr['allowed_phpconfigs'] = array(); + if (! empty($p_allowed_phpconfigs) && is_array($p_allowed_phpconfigs)) { + foreach ($p_allowed_phpconfigs as $allowed_phpconfig) { + $allowed_phpconfig = intval($allowed_phpconfig); + $value_arr['allowed_phpconfigs'][] = $allowed_phpconfig; + } + } + $value_arr['allowed_phpconfigs'] = array_map('intval', $value_arr['allowed_phpconfigs']); + + $ins_stmt = Database::prepare(" + INSERT INTO `" . TABLE_PANEL_PLANS . "` + SET `adminid` = :adminid, `name` = :name, `description` = :desc, `value` = :valuearr, `ts` = UNIX_TIMESTAMP(); + "); + $ins_data = array( + 'adminid' => $this->getUserDetail('adminid'), + 'name' => $name, + 'desc' => $description, + 'valuearr' => json_encode($value_arr) + ); + Database::pexecute($ins_stmt, $ins_data, true, true); + $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added hosting-plan '" . $name . "'"); + $result = $this->apiCall('HostingPlans.get', array( + 'planname' => $name + )); + return $this->response(200, "successfull", $result); + } + throw new \Exception("Not allowed to execute given command.", 403); + } + + /** + * update hosting-plan by either id or plan-name + * + * @param int $id + * optional the hosting-plan-id + * @param string $planname + * optional the hosting-plan-name + * @param string $name + * optional name of the plan + * @param string $description + * optional description for hosting-plan + * @param int $diskspace + * optional disk-space available for customer in MB, default 0 + * @param bool $diskspace_ul + * optional, whether customer should have unlimited diskspace, default 0 (false) + * @param int $traffic + * optional traffic available for customer in GB, default 0 + * @param bool $traffic_ul + * optional, whether customer should have unlimited traffic, default 0 (false) + * @param int $subdomains + * optional amount of subdomains available for customer, default 0 + * @param bool $subdomains_ul + * optional, whether customer should have unlimited subdomains, default 0 (false) + * @param int $emails + * optional amount of emails available for customer, default 0 + * @param bool $emails_ul + * optional, whether customer should have unlimited emails, default 0 (false) + * @param int $email_accounts + * optional amount of email-accounts available for customer, default 0 + * @param bool $email_accounts_ul + * optional, whether customer should have unlimited email-accounts, default 0 (false) + * @param int $email_forwarders + * optional amount of email-forwarders available for customer, default 0 + * @param bool $email_forwarders_ul + * optional, whether customer should have unlimited email-forwarders, default 0 (false) + * @param int $email_quota + * optional size of email-quota available for customer in MB, default is system-setting mail_quota + * @param bool $email_quota_ul + * optional, whether customer should have unlimited email-quota, default 0 (false) + * @param bool $email_imap + * optional, whether to allow IMAP access, default 0 (false) + * @param bool $email_pop3 + * optional, whether to allow POP3 access, default 0 (false) + * @param int $ftps + * optional amount of ftp-accounts available for customer, default 0 + * @param bool $ftps_ul + * optional, whether customer should have unlimited ftp-accounts, default 0 (false) + * @param int $mysqls + * optional amount of mysql-databases available for customer, default 0 + * @param bool $mysqls_ul + * optional, whether customer should have unlimited mysql-databases, default 0 (false) + * @param bool $phpenabled + * optional, whether to allow usage of PHP, default 0 (false) + * @param array $allowed_phpconfigs + * optional, array of IDs of php-config that the customer is allowed to use, default empty (none) + * @param bool $perlenabled + * optional, whether to allow usage of Perl/CGI, default 0 (false) + * @param bool $dnsenabled + * optional, ether to allow usage of the DNS editor (requires activated nameserver in settings), default 0 (false) + * @param bool $logviewenabled + * optional, ether to allow acccess to webserver access/error-logs, default 0 (false) + * + * @access admin + * @throws \Exception + * @return string json-encoded array + */ + public function update() + { + if ($this->isAdmin()) { + + // parameters + $id = $this->getParam('id', true, 0); + $dn_optional = ($id <= 0 ? false : true); + $planname = $this->getParam('planname', $dn_optional, ''); + + // get requested hosting-plan + $result = $this->apiCall('HostingPlans.get', array( + 'id' => $id, + 'planname' => $planname + )); + $id = $result['id']; + + $result['value'] = json_decode($result['value'], true); + foreach ($result['value'] as $index => $value) { + $result[$index] = $value; + } + + $name = $this->getParam('name', true, $result['name']); + $description = $this->getParam('description', true, $result['description']); + + $value_arr = array(); + $value_arr['diskspace'] = $this->getUlParam('diskspace', 'diskspace_ul', true, $result['diskspace']); + $value_arr['traffic'] = $this->getUlParam('traffic', 'traffic_ul', true, $result['traffic']); + $value_arr['subdomains'] = $this->getUlParam('subdomains', 'subdomains_ul', true, $result['subdomains']); + $value_arr['emails'] = $this->getUlParam('emails', 'emails_ul', true, $result['emails']); + $value_arr['email_accounts'] = $this->getUlParam('email_accounts', 'email_accounts_ul', true, $result['email_accounts']); + $value_arr['email_forwarders'] = $this->getUlParam('email_forwarders', 'email_forwarders_ul', true, $result['email_forwarders']); + $value_arr['email_quota'] = $this->getUlParam('email_quota', 'email_quota_ul', true, $result['email_quota']); + $value_arr['email_imap'] = $this->getParam('email_imap', true, $result['email_imap']); + $value_arr['email_pop3'] = $this->getParam('email_pop3', true, $result['email_pop3']); + $value_arr['ftps'] = $this->getUlParam('ftps', 'ftps_ul', true, $result['ftps']); + $value_arr['mysqls'] = $this->getUlParam('mysqls', 'mysqls_ul', true, $result['mysqls']); + $value_arr['phpenabled'] = $this->getBoolParam('phpenabled', true, $result['phpenabled']); + $p_allowed_phpconfigs = $this->getParam('allowed_phpconfigs', true, $result['allowed_phpconfigs']); + $value_arr['perlenabled'] = $this->getBoolParam('perlenabled', true, $result['perlenabled']); + $value_arr['dnsenabled'] = $this->getBoolParam('dnsenabled', true, $result['dnsenabled']); + $value_arr['logviewenabled'] = $this->getBoolParam('logviewenabled', true, $result['logviewenabled']); + + // validation + $name = \Froxlor\Validate\Validate::validate(trim($name), 'name', '', '', array(), true); + $description = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $description), 'description', '/^[^\0]*$/'); + + if (Settings::Get('system.mail_quota_enabled') != '1') { + $value_arr['email_quota'] = - 1; + } + + if (empty($name)) { + $name = $result['name']; + } + + $value_arr['allowed_phpconfigs'] = array(); + if (! empty($p_allowed_phpconfigs) && is_array($p_allowed_phpconfigs)) { + foreach ($p_allowed_phpconfigs as $allowed_phpconfig) { + $allowed_phpconfig = intval($allowed_phpconfig); + $value_arr['allowed_phpconfigs'][] = $allowed_phpconfig; + } + } + $value_arr['allowed_phpconfigs'] = array_map('intval', $value_arr['allowed_phpconfigs']); + + $upd_stmt = Database::prepare(" + UPDATE `" . TABLE_PANEL_PLANS . "` + SET `name` = :name, `description` = :desc, `value` = :valuearr, `ts` = UNIX_TIMESTAMP() + WHERE `id` = :id + "); + $update_data = array( + 'name' => $name, + 'desc' => $description, + 'valuearr' => json_encode($value_arr), + 'id' => $id + ); + Database::pexecute($upd_stmt, $update_data, true, true); + $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] updated hosting-plan '" . $result['name'] . "'"); + return $this->response(200, "successfull", $update_data); + } + throw new \Exception("Not allowed to execute given command.", 403); + } + + /** + * delete hosting-plan by either id or plan-name + * + * @param int $id + * optional the hosting-plan-id + * @param string $planname + * optional the hosting-plan-name + * + * @access admin + * @throws \Exception + * @return string json-encoded array + */ public function delete() { - throw new \Exception('noop', 303); + if ($this->isAdmin()) { + $id = $this->getParam('id', true, 0); + $dn_optional = ($id <= 0 ? false : true); + $planname = $this->getParam('planname', $dn_optional, ''); + + // get requested hosting-plan + $result = $this->apiCall('HostingPlans.get', array( + 'id' => $id, + 'planname' => $planname + )); + $id = $result['id']; + + $del_stmt = Database::prepare(" + DELETE FROM `" . TABLE_PANEL_PLANS . "` WHERE `id` = :id + "); + Database::pexecute($del_stmt, array( + 'id' => $id + ), true, true); + $this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted hosting-plan '" . $result['name'] . "'"); + return $this->response(200, "successfull", $result); + } + throw new \Exception("Not allowed to execute given command.", 403); } } diff --git a/lib/Froxlor/Api/Commands/IpsAndPorts.php b/lib/Froxlor/Api/Commands/IpsAndPorts.php index 6ce764bc..b0a9f05e 100644 --- a/lib/Froxlor/Api/Commands/IpsAndPorts.php +++ b/lib/Froxlor/Api/Commands/IpsAndPorts.php @@ -118,6 +118,14 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour * optional, requires $ssl = 1, default empty * @param string $ssl_cert_chainfile * optional, requires $ssl = 1, default empty + * @param string $ssl_specialsettings + * optional, requires $ssl = 1, default empty + * @param bool $include_specialsettings + * optional, requires $ssl = 1, whether or not to include non-ssl specialsettings, default false + * @param string $ssl_default_vhostconf_domain + * optional, requires $ssl = 1, defatul empty + * @param bool $include_default_vhostconf_domain + * optional, requires $ssl = 1, whether or not to include non-ssl default_vhostconf_domain, default false * * @access admin * @throws \Exception @@ -146,12 +154,20 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour $ssl_key_file = \Froxlor\Validate\Validate::validate($this->getParam('ssl_key_file', $ssl, ''), 'ssl_key_file', '', '', array(), true); $ssl_ca_file = \Froxlor\Validate\Validate::validate($this->getParam('ssl_ca_file', true, ''), 'ssl_ca_file', '', '', array(), true); $ssl_cert_chainfile = \Froxlor\Validate\Validate::validate($this->getParam('ssl_cert_chainfile', true, ''), 'ssl_cert_chainfile', '', '', array(), true); + $ssl_specialsettings = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('ssl_specialsettings', true, '')), 'ssl_specialsettings', '/^[^\0]*$/', '', array(), true); + $include_specialsettings = ! empty($this->getBoolParam('include_specialsettings', true, 0)) ? 1 : 0; + $ssl_default_vhostconf_domain = \Froxlor\Validate\Validate::validate(str_replace("\r\n", "\n", $this->getParam('ssl_default_vhostconf_domain', true, '')), 'ssl_default_vhostconf_domain', '/^[^\0]*$/', '', array(), true); + $include_default_vhostconf_domain = ! empty($this->getBoolParam('include_default_vhostconf_domain', true, 0)) ? 1 : 0; } else { $ssl = 0; $ssl_cert_file = ''; $ssl_key_file = ''; $ssl_ca_file = ''; $ssl_cert_chainfile = ''; + $ssl_specialsettings = ''; + $include_specialsettings = 0; + $ssl_default_vhostconf_domain = ''; + $include_default_vhostconf_domain = 0; } if ($listen_statement != '1') { @@ -217,7 +233,9 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour `specialsettings` = :ss, `ssl` = :ssl, `ssl_cert_file` = :ssl_cert, `ssl_key_file` = :ssl_key, `ssl_ca_file` = :ssl_ca, `ssl_cert_chainfile` = :ssl_chain, - `default_vhostconf_domain` = :dvhd, `docroot` = :docroot; + `default_vhostconf_domain` = :dvhd, `docroot` = :docroot, + `ssl_specialsettings` = :ssl_ss, `include_specialsettings` = :incss, + `ssl_default_vhostconf_domain` = :ssl_dvhd, `include_default_vhostconf_domain` = :incdvhd; "); $ins_data = array( 'ip' => $ip, @@ -233,7 +251,11 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour 'ssl_ca' => $ssl_ca_file, 'ssl_chain' => $ssl_cert_chainfile, 'dvhd' => $default_vhostconf_domain, - 'docroot' => $docroot + 'docroot' => $docroot, + 'ssl_ss' => $ssl_specialsettings, + 'incss' => $include_specialsettings, + 'ssl_dvhd' => $ssl_default_vhostconf_domain, + 'incdvhd' => $include_default_vhostconf_domain ); Database::pexecute($ins_stmt, $ins_data); $ins_data['id'] = Database::lastInsertId(); @@ -287,6 +309,14 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour * optional, requires $ssl = 1, default empty * @param string $ssl_cert_chainfile * optional, requires $ssl = 1, default empty + * @param string $ssl_specialsettings + * optional, requires $ssl = 1, default empty + * @param bool $include_specialsettings + * optional, requires $ssl = 1, whether or not to include non-ssl specialsettings, default false + * @param string $ssl_default_vhostconf_domain + * optional, requires $ssl = 1, defatul empty + * @param bool $include_default_vhostconf_domain + * optional, requires $ssl = 1, whether or not to include non-ssl default_vhostconf_domain, default false * * * @access admin @@ -321,12 +351,20 @@ 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', '/^[^\0]*$/', '', 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', '/^[^\0]*$/', '', array(), true); + $include_default_vhostconf_domain = $this->getBoolParam('include_default_vhostconf_domain', true, $result['include_default_vhostconf_domain']); } else { $ssl = 0; $ssl_cert_file = ''; $ssl_key_file = ''; $ssl_ca_file = ''; $ssl_cert_chainfile = ''; + $ssl_specialsettings = ''; + $include_specialsettings = 0; + $ssl_default_vhostconf_domain = ''; + $include_default_vhostconf_domain = 0; } $result_checkfordouble_stmt = Database::prepare(" @@ -404,7 +442,9 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour `specialsettings` = :ss, `ssl` = :ssl, `ssl_cert_file` = :ssl_cert, `ssl_key_file` = :ssl_key, `ssl_ca_file` = :ssl_ca, `ssl_cert_chainfile` = :ssl_chain, - `default_vhostconf_domain` = :dvhd, `docroot` = :docroot + `default_vhostconf_domain` = :dvhd, `docroot` = :docroot, + `ssl_specialsettings` = :ssl_ss, `include_specialsettings` = :incss, + `ssl_default_vhostconf_domain` = :ssl_dvhd, `include_default_vhostconf_domain` = :incdvhd WHERE `id` = :id; "); $upd_data = array( @@ -422,6 +462,10 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour 'ssl_chain' => $ssl_cert_chainfile, 'dvhd' => $default_vhostconf_domain, 'docroot' => $docroot, + 'ssl_ss' => $ssl_specialsettings, + 'incss' => $include_specialsettings, + 'ssl_dvhd' => $ssl_default_vhostconf_domain, + 'incdvhd' => $include_default_vhostconf_domain, 'id' => $id ); Database::pexecute($upd_stmt, $upd_data); diff --git a/lib/Froxlor/Api/Commands/Mysqls.php b/lib/Froxlor/Api/Commands/Mysqls.php index 54109919..35f6062c 100644 --- a/lib/Froxlor/Api/Commands/Mysqls.php +++ b/lib/Froxlor/Api/Commands/Mysqls.php @@ -33,7 +33,7 @@ class Mysqls extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEnt * optional, description for database * @param bool $sendinfomail * optional, send created resource-information to customer, default: false - * @param int $customer_id + * @param int $customerid * required when called as admin, not needed when called as customer * * @access admin, customer diff --git a/lib/Froxlor/Api/Commands/SubDomains.php b/lib/Froxlor/Api/Commands/SubDomains.php index dbe329e5..00847da9 100644 --- a/lib/Froxlor/Api/Commands/SubDomains.php +++ b/lib/Froxlor/Api/Commands/SubDomains.php @@ -45,6 +45,8 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc * optional, whether to generate a https-redirect or not, default false; requires SSL to be enabled * @param bool $letsencrypt * optional, whether to generate a Let's Encrypt certificate for this domain, default false; requires SSL to be enabled + * @param bool $http2 + * optional, whether to enable http/2 for this subdomain (requires to be enabled in the settings), default 0 (false) * @param int $hsts_maxage * optional max-age value for HSTS header, default 0 * @param bool $hsts_sub @@ -76,12 +78,14 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc if (Settings::Get('system.use_ssl')) { $ssl_redirect = $this->getBoolParam('ssl_redirect', true, 0); $letsencrypt = $this->getBoolParam('letsencrypt', true, 0); + $http2 = $this->getBoolParam('http2', true, 0); $hsts_maxage = $this->getParam('hsts_maxage', true, 0); $hsts_sub = $this->getBoolParam('hsts_sub', true, 0); $hsts_preload = $this->getBoolParam('hsts_preload', true, 0); } else { $ssl_redirect = 0; $letsencrypt = 0; + $http2 = 0; $hsts_maxage = 0; $hsts_sub = 0; $hsts_preload = 0; @@ -241,7 +245,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc $phpsid_result['phpsettingid'] = intval($phpsettingid); } - // acutall insert domain + // actually insert domain $stmt = Database::prepare(" INSERT INTO `" . TABLE_PANEL_DOMAINS . "` SET `customerid` = :customerid, @@ -258,12 +262,20 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc `openbasedir_path` = :openbasedir_path, `speciallogfile` = :speciallogfile, `specialsettings` = :specialsettings, + `ssl_specialsettings` = :ssl_specialsettings, + `include_specialsettings` = :include_specialsettings, `ssl_redirect` = :ssl_redirect, `phpsettingid` = :phpsettingid, `letsencrypt` = :letsencrypt, + `http2` = :http2, `hsts` = :hsts, `hsts_sub` = :hsts_sub, - `hsts_preload` = :hsts_preload + `hsts_preload` = :hsts_preload, + `ocsp_stapling` = :ocsp_stapling, + `override_tls` = :override_tls, + `ssl_protocols` = :ssl_protocols, + `ssl_cipher_list` = :ssl_cipher_list, + `tlsv13_cipher_list` = :tlsv13_cipher_list "); $params = array( "customerid" => $customer['customerid'], @@ -280,12 +292,20 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc "phpenabled" => $domain_check['phpenabled'], "speciallogfile" => $domain_check['speciallogfile'], "specialsettings" => $domain_check['specialsettings'], + "ssl_specialsettings" => $domain_check['ssl_specialsettings'], + "include_specialsettings" => $domain_check['include_specialsettings'], "ssl_redirect" => $ssl_redirect, "phpsettingid" => $phpsid_result['phpsettingid'], "letsencrypt" => $letsencrypt, + "http2" => $http2, "hsts" => $hsts_maxage, "hsts_sub" => $hsts_sub, - "hsts_preload" => $hsts_preload + "hsts_preload" => $hsts_preload, + "ocsp_stapling" => $domain_check['ocsp_stapling'], + "override_tls" => $domain_check['override_tls'], + "ssl_protocols" => $domain_check['ssl_protocols'], + "ssl_cipher_list" => $domain_check['ssl_cipher_list'], + "tlsv13_cipher_list" => $domain_check['tlsv13_cipher_list'] ); Database::pexecute($stmt, $params, true, true); $subdomain_id = Database::lastInsertId(); @@ -430,6 +450,8 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc * optional, whether to generate a https-redirect or not, default false; requires SSL to be enabled * @param bool $letsencrypt * optional, whether to generate a Let's Encrypt certificate for this domain, default false; requires SSL to be enabled + * @param bool $http2 + * optional, whether to enable http/2 for this domain (requires to be enabled in the settings), default 0 (false) * @param int $hsts_maxage * optional max-age value for HSTS header * @param bool $hsts_sub @@ -473,12 +495,14 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc if (Settings::Get('system.use_ssl')) { $ssl_redirect = $this->getBoolParam('ssl_redirect', true, $result['ssl_redirect']); $letsencrypt = $this->getBoolParam('letsencrypt', true, $result['letsencrypt']); + $http2 = $this->getBoolParam('http2', true, $result['http2']); $hsts_maxage = $this->getParam('hsts_maxage', true, $result['hsts']); $hsts_sub = $this->getBoolParam('hsts_sub', true, $result['hsts_sub']); $hsts_preload = $this->getBoolParam('hsts_preload', true, $result['hsts_preload']); } else { $ssl_redirect = 0; $letsencrypt = 0; + $http2 = 0; $hsts_maxage = 0; $hsts_sub = 0; $hsts_preload = 0; @@ -554,15 +578,10 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc } } - // We can't enable let's encrypt for wildcard - domains when using acme-v1 - if ($iswildcarddomain == '1' && $letsencrypt == '1' && Settings::Get('system.leapiversion') == '1') { + // We can't enable let's encrypt for wildcard-domains + if ($iswildcarddomain == '1' && $letsencrypt == '1') { \Froxlor\UI\Response::standard_error('nowildcardwithletsencrypt'); } - // if using acme-v2 we cannot issue wildcard-certificates - // because they currently only support the dns-01 challenge - if ($iswildcarddomain == '1' && $letsencrypt == '1' && Settings::Get('system.leapiversion') == '2') { - \Froxlor\UI\Response::standard_error('nowildcardwithletsencryptv2'); - } // Temporarily deactivate ssl_redirect until Let's Encrypt certificate was generated if ($ssl_redirect > 0 && $letsencrypt == 1 && $result['letsencrypt'] != $letsencrypt) { @@ -599,6 +618,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc `openbasedir_path`= :openbasedir_path, `ssl_redirect`= :ssl_redirect, `letsencrypt`= :letsencrypt, + `http2` = :http2, `hsts` = :hsts, `hsts_sub` = :hsts_sub, `hsts_preload` = :hsts_preload, @@ -614,6 +634,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc "openbasedir_path" => $openbasedir_path, "ssl_redirect" => $ssl_redirect, "letsencrypt" => $letsencrypt, + "http2" => $http2, "hsts" => $hsts_maxage, "hsts_sub" => $hsts_sub, "hsts_preload" => $hsts_preload, @@ -623,13 +644,20 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc ); Database::pexecute($stmt, $params, true, true); - if ($result['aliasdomain'] != $aliasdomain) { + if ($result['aliasdomain'] != $aliasdomain && is_numeric($result['aliasdomain'])) { // trigger when domain id for alias destination has changed: both for old and new destination \Froxlor\Domain\Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger()); \Froxlor\Domain\Domain::triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $this->logger()); - } elseif ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) { + } + if ($result['wwwserveralias'] != $wwwserveralias || $result['letsencrypt'] != $letsencrypt) { // or when wwwserveralias or letsencrypt was changed \Froxlor\Domain\Domain::triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $this->logger()); + if ((int) $aliasdomain === 0) { + // in case the wwwserveralias is set on a main domain, $aliasdomain is 0 + // --> the call just above to triggerLetsEncryptCSRForAliasDestinationDomain + // is a noop...let's repeat it with the domain id of the main domain + \Froxlor\Domain\Domain::triggerLetsEncryptCSRForAliasDestinationDomain($id, $this->logger()); + } } // check whether LE has been disabled, so we remove the certificate @@ -828,6 +856,8 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc \Froxlor\System\Cronjob::inserttask('4'); // remove domains DNS from powerDNS if used, #581 \Froxlor\System\Cronjob::inserttask('11', $result['domain']); + // remove domain from acme.sh / lets encrypt if used + \Froxlor\System\Cronjob::inserttask('12', $result['domain']); // reduce subdomain-usage-counter Customers::decreaseUsage($customer['customerid'], 'subdomains_used'); @@ -852,7 +882,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc { // check whether an URL was specified $_doredirect = false; - if (! empty($url) && \Froxlor\Validate\Form\Data::validateUrl($url)) { + if (! empty($url) && \Froxlor\Validate\Validate::validateUrl($url)) { $path = $url; $_doredirect = true; } else { @@ -860,7 +890,7 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc } // check whether path is a real path - if (! preg_match('/^https?\:\/\//', $path) || ! \Froxlor\Validate\Form\Data::validateUrl($path)) { + if (! preg_match('/^https?\:\/\//', $path) || ! \Froxlor\Validate\Validate::validateUrl($path)) { if (strstr($path, ":") !== false) { \Froxlor\UI\Response::standard_error('pathmaynotcontaincolon', '', true); } diff --git a/lib/Froxlor/Api/FroxlorRPC.php b/lib/Froxlor/Api/FroxlorRPC.php index d96e2c7c..f4dce617 100644 --- a/lib/Froxlor/Api/FroxlorRPC.php +++ b/lib/Froxlor/Api/FroxlorRPC.php @@ -55,13 +55,20 @@ class FroxlorRPC */ private static function validateAuth($key, $secret) { - $sel_stmt = \Froxlor\Database\Database::prepare("SELECT * FROM `api_keys` WHERE `apikey` = :ak AND `secret` = :as"); + $sel_stmt = \Froxlor\Database\Database::prepare(" + SELECT ak.*, a.api_allowed as admin_api_allowed, c.api_allowed as cust_api_allowed + FROM `api_keys` ak + LEFT JOIN `panel_admins` a ON a.adminid = ak.adminid + LEFT JOIN `panel_customers` c ON c.customerid = ak.customerid + WHERE `apikey` = :ak AND `secret` = :as + "); $result = \Froxlor\Database\Database::pexecute_first($sel_stmt, array( 'ak' => $key, 'as' => $secret ), true, true); if ($result) { - if ($result['apikey'] == $key && $result['secret'] == $secret && ($result['valid_until'] == - 1 || $result['valid_until'] >= time())) { + if ($result['apikey'] == $key && $result['secret'] == $secret && ($result['valid_until'] == - 1 || $result['valid_until'] >= time()) && (($result['customerid'] == 0 && $result['admin_api_allowed'] == 1) || ($result['customerid'] > 0 && $result['cust_api_allowed'] == 1))) { + // get user to check whether api call is allowed if (! empty($result['allowed_from'])) { // @todo allow specification and validating of whole subnets later $ip_list = explode(",", $result['allowed_from']); diff --git a/lib/Froxlor/Cli/Action/ConfigServicesAction.php b/lib/Froxlor/Cli/Action/ConfigServicesAction.php index ca472b10..fccddc5f 100644 --- a/lib/Froxlor/Cli/Action/ConfigServicesAction.php +++ b/lib/Froxlor/Cli/Action/ConfigServicesAction.php @@ -103,7 +103,7 @@ class ConfigServicesAction extends \Froxlor\Cli\Action echo PHP_EOL; while (! in_array($_daemons_config['distro'], $distributions_select_data)) { - $_daemons_config['distro'] = ConfigServicesCmd::getInput("choose distribution", "stretch"); + $_daemons_config['distro'] = ConfigServicesCmd::getInput("choose distribution", "buster"); } // go through all services and let user check whether to include it or not diff --git a/lib/Froxlor/Cli/ConfigServicesCmd.php b/lib/Froxlor/Cli/ConfigServicesCmd.php old mode 100755 new mode 100644 diff --git a/lib/Froxlor/Cli/SwitchServerIpCmd.php b/lib/Froxlor/Cli/SwitchServerIpCmd.php old mode 100755 new mode 100644 diff --git a/lib/Froxlor/Cron/CronConfig.php b/lib/Froxlor/Cron/CronConfig.php index e5916ed0..5c8e5cfc 100644 --- a/lib/Froxlor/Cron/CronConfig.php +++ b/lib/Froxlor/Cron/CronConfig.php @@ -61,6 +61,7 @@ class CronConfig $month_delay = 7; while ($row_cronentry = $result_stmt->fetch(\PDO::FETCH_ASSOC)) { // create cron.d-entry + $matches = array(); if (preg_match("/(\d+) (MINUTE|HOUR|DAY|WEEK|MONTH)/", $row_cronentry['interval'], $matches)) { if ($matches[1] == 1) { $minvalue = "*"; @@ -101,7 +102,7 @@ class CronConfig $binpath = "/usr/bin/nice -n 5 /usr/bin/php5 -q"; } - $cronfile .= "root " . $binpath . " " . \Froxlor\Froxlor::getInstallDir() . "/scripts/froxlor_master_cronjob.php --" . $row_cronentry['cronfile'] . " 1> /dev/null\n"; + $cronfile .= "root " . $binpath . " " . \Froxlor\FileDir::makeCorrectFile(\Froxlor\Froxlor::getInstallDir() . "/scripts/froxlor_master_cronjob.php") . " --" . $row_cronentry['cronfile'] . " 1> /dev/null\n"; } } diff --git a/lib/Froxlor/Cron/Dns/PowerDNS.php b/lib/Froxlor/Cron/Dns/PowerDNS.php index 76e7bddd..fa0e8d69 100644 --- a/lib/Froxlor/Cron/Dns/PowerDNS.php +++ b/lib/Froxlor/Cron/Dns/PowerDNS.php @@ -111,7 +111,7 @@ class PowerDNS extends DnsBase private function insertZone($domainname, $serial = 0) { - $ins_stmt = PowerDNS::getDB()->prepare(" + $ins_stmt = \Froxlor\Dns\PowerDNS::getDB()->prepare(" INSERT INTO domains set `name` = :domainname, `notified_serial` = :serial, `type` = 'NATIVE' "); $ins_stmt->execute(array( @@ -124,7 +124,7 @@ class PowerDNS extends DnsBase private function insertRecords($domainid = 0, $records = array(), $origin = "") { - $ins_stmt = PowerDNS::getDB()->prepare(" + $ins_stmt = \Froxlor\Dns\PowerDNS::getDB()->prepare(" INSERT INTO records set `domain_id` = :did, `name` = :rec, @@ -161,7 +161,7 @@ class PowerDNS extends DnsBase private function insertAllowedTransfers($domainid) { - $ins_stmt = PowerDNS::getDB()->prepare(" + $ins_stmt = \Froxlor\Dns\PowerDNS::getDB()->prepare(" INSERT INTO domainmetadata set `domain_id` = :did, `kind` = 'ALLOW-AXFR-FROM', `content` = :value "); diff --git a/lib/Froxlor/Cron/Http/Apache.php b/lib/Froxlor/Cron/Http/Apache.php index 2a6a9058..6fd05880 100644 --- a/lib/Froxlor/Cron/Http/Apache.php +++ b/lib/Froxlor/Cron/Http/Apache.php @@ -3,7 +3,6 @@ namespace Froxlor\Cron\Http; use Froxlor\Database\Database; use Froxlor\Settings; -use Froxlor\Cron\Http\Php\Fpm; use Froxlor\Cron\Http\Php\PhpInterface; /** @@ -46,30 +45,6 @@ class Apache extends HttpConfigBase */ private $deactivated = false; - public function reload() - { - if ((int) Settings::Get('phpfpm.enabled') == 1) { - // get all start/stop commands - $startstop_sel = Database::prepare("SELECT reload_cmd, config_dir FROM `" . TABLE_PANEL_FPMDAEMONS . "`"); - Database::pexecute($startstop_sel); - $restart_cmds = $startstop_sel->fetchAll(\PDO::FETCH_ASSOC); - // restart all php-fpm instances - foreach ($restart_cmds as $restart_cmd) { - // check whether the config dir is empty (no domains uses this daemon) - // so we need to create a dummy - $_conffiles = glob(\Froxlor\FileDir::makeCorrectFile($restart_cmd['config_dir'] . "/*.conf")); - if ($_conffiles === false || empty($_conffiles)) { - \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'apache::reload: fpm config directory "' . $restart_cmd['config_dir'] . '" is empty. Creating dummy.'); - Fpm::createDummyPool($restart_cmd['config_dir']); - } - \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'apache::reload: running ' . $restart_cmd['reload_cmd']); - \Froxlor\FileDir::safe_exec(escapeshellcmd($restart_cmd['reload_cmd'])); - } - } - \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'apache::reload: reloading apache'); - \Froxlor\FileDir::safe_exec(escapeshellcmd(Settings::Get('system.apachereload_command'))); - } - /** * define a standard -statement, bug #32 */ @@ -144,7 +119,7 @@ class Apache extends HttpConfigBase foreach ($statusCodes as $statusCode) { if (Settings::Get('defaultwebsrverrhandler.err' . $statusCode) != '') { $defhandler = Settings::Get('defaultwebsrverrhandler.err' . $statusCode); - if (! \Froxlor\Validate\Form\Data::validateUrl($defhandler)) { + if (! \Froxlor\Validate\Validate::validateUrl($defhandler)) { if (substr($defhandler, 0, 1) != '"' && substr($defhandler, - 1, 1) != '"') { $defhandler = '"' . \Froxlor\FileDir::makeCorrectFile($defhandler) . '"'; } @@ -203,7 +178,7 @@ class Apache extends HttpConfigBase $this->virtualhosts_data[$vhosts_filename] .= ' ServerName ' . Settings::Get('system.hostname') . "\n"; $froxlor_aliases = Settings::Get('system.froxloraliases'); - if (!empty($froxlor_aliases)) { + if (! empty($froxlor_aliases)) { $froxlor_aliases = explode(",", $froxlor_aliases); $aliases = ""; foreach ($froxlor_aliases as $falias) { @@ -212,7 +187,7 @@ class Apache extends HttpConfigBase } } $aliases = trim($aliases); - if (!empty($aliases)) { + if (! empty($aliases)) { $this->virtualhosts_data[$vhosts_filename] .= ' ServerAlias ' . $aliases . "\n"; } } @@ -428,11 +403,16 @@ class Apache extends HttpConfigBase * end of dirprotection */ - if ($row_ipsandports['specialsettings'] != '') { + if ($row_ipsandports['specialsettings'] != '' && ($row_ipsandports['ssl'] == '0' || ($row_ipsandports['ssl'] == '1' && Settings::Get('system.use_ssl') == '1' && $row_ipsandports['include_specialsettings'] == '1'))) { $this->virtualhosts_data[$vhosts_filename] .= $this->processSpecialConfigTemplate($row_ipsandports['specialsettings'], $domain, $row_ipsandports['ip'], $row_ipsandports['port'], $row_ipsandports['ssl'] == '1') . "\n"; } if ($row_ipsandports['ssl'] == '1' && Settings::Get('system.use_ssl') == '1') { + + if ($row_ipsandports['ssl_specialsettings'] != '') { + $this->virtualhosts_data[$vhosts_filename] .= $this->processSpecialConfigTemplate($row_ipsandports['ssl_specialsettings'], $domain, $row_ipsandports['ip'], $row_ipsandports['port'], $row_ipsandports['ssl'] == '1') . "\n"; + } + if ($row_ipsandports['ssl_cert_file'] == '') { $row_ipsandports['ssl_cert_file'] = Settings::Get('system.ssl_cert_file'); if (! file_exists($row_ipsandports['ssl_cert_file'])) { @@ -502,6 +482,10 @@ class Apache extends HttpConfigBase // this makes it more secure, thx to Marcel (08/2013) $this->virtualhosts_data[$vhosts_filename] .= ' SSLHonorCipherOrder On' . "\n"; $this->virtualhosts_data[$vhosts_filename] .= ' SSLCipherSuite ' . Settings::Get('system.ssl_cipher_list') . "\n"; + $protocols = array_map('trim', explode(",", Settings::Get('system.ssl_protocols'))); + if (in_array("TLSv1.3", $protocols) && ! empty(Settings::Get('system.tlsv13_cipher_list')) && Settings::Get('system.apache24') == 1) { + $this->virtualhosts_data[$vhosts_filename] .= ' SSLCipherSuite TLSv1.3 ' . Settings::Get('system.tlsv13_cipher_list') . "\n"; + } $this->virtualhosts_data[$vhosts_filename] .= ' SSLVerifyDepth 10' . "\n"; $this->virtualhosts_data[$vhosts_filename] .= ' SSLCertificateFile ' . \Froxlor\FileDir::makeCorrectFile($domain['ssl_cert_file']) . "\n"; @@ -921,9 +905,12 @@ class Apache extends HttpConfigBase $ipport = $domain['ip'] . ':' . $domain['port'] . ' '; } - if ($ipandport['default_vhostconf_domain'] != '') { + if ($ipandport['default_vhostconf_domain'] != '' && ($ssl_vhost == false || ($ssl_vhost == true && $ipandport['include_default_vhostconf_domain'] == '1'))) { $_vhost_content .= $this->processSpecialConfigTemplate($ipandport['default_vhostconf_domain'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; } + if ($ipandport['ssl_default_vhostconf_domain'] != '' && $ssl_vhost == true) { + $_vhost_content .= $this->processSpecialConfigTemplate($ipandport['ssl_default_vhostconf_domain'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; + } $ipportlist .= $ipport; } @@ -949,7 +936,7 @@ class Apache extends HttpConfigBase 'domainid' => $domain['id'] )); - if ($ssldestport['port'] != '') { + if ($ssldestport && $ssldestport['port'] != '') { $_sslport = ":" . $ssldestport['port']; } @@ -980,11 +967,16 @@ class Apache extends HttpConfigBase } if ($domain['ssl_cert_file'] != '') { + + $ssl_protocols = ($domain['override_tls'] == '1' && ! empty($domain['ssl_protocols'])) ? $domain['ssl_protocols'] : Settings::Get('system.ssl_protocols'); + $ssl_cipher_list = ($domain['override_tls'] == '1' && ! empty($domain['ssl_cipher_list'])) ? $domain['ssl_cipher_list'] : Settings::Get('system.ssl_cipher_list'); + $tlsv13_cipher_list = ($domain['override_tls'] == '1' && ! empty($domain['tlsv13_cipher_list'])) ? $domain['tlsv13_cipher_list'] : Settings::Get('system.tlsv13_cipher_list'); + $vhost_content .= ' SSLEngine On' . "\n"; - $vhost_content .= ' SSLProtocol -ALL +' . str_replace(",", " +", Settings::Get('system.ssl_protocols')) . "\n"; + $vhost_content .= ' SSLProtocol -ALL +' . str_replace(",", " +", $ssl_protocols) . "\n"; if (Settings::Get('system.apache24') == '1') { if (isset($domain['http2']) && $domain['http2'] == '1' && Settings::Get('system.http2_support') == '1') { - $vhost_content .= ' Protocols h2 http/1.1' . "\n"; + $vhost_content .= ' Protocols h2 http/1.1' . "\n"; } if (! empty(Settings::Get('system.dhparams_file'))) { $dhparams = \Froxlor\FileDir::makeCorrectFile(Settings::Get('system.dhparams_file')); @@ -997,7 +989,11 @@ class Apache extends HttpConfigBase } // this makes it more secure, thx to Marcel (08/2013) $vhost_content .= ' SSLHonorCipherOrder On' . "\n"; - $vhost_content .= ' SSLCipherSuite ' . Settings::Get('system.ssl_cipher_list') . "\n"; + $vhost_content .= ' SSLCipherSuite ' . $ssl_cipher_list . "\n"; + $protocols = array_map('trim', explode(",", $ssl_protocols)); + if (in_array("TLSv1.3", $protocols) && ! empty($tlsv13_cipher_list) && Settings::Get('system.apache24') == 1) { + $vhost_content .= ' SSLCipherSuite TLSv1.3 ' . $tlsv13_cipher_list . "\n"; + } $vhost_content .= ' SSLVerifyDepth 10' . "\n"; $vhost_content .= ' SSLCertificateFile ' . \Froxlor\FileDir::makeCorrectFile($domain['ssl_cert_file']) . "\n"; @@ -1074,17 +1070,25 @@ class Apache extends HttpConfigBase } $vhost_content .= $this->getLogfiles($domain); - if ($domain['specialsettings'] != '') { + if ($domain['specialsettings'] != '' && ($ssl_vhost == false || ($ssl_vhost == true && $domain['include_specialsettings'] == 1))) { $vhost_content .= $this->processSpecialConfigTemplate($domain['specialsettings'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; } + if ($domain['ssl_specialsettings'] != '' && $ssl_vhost == true) { + $vhost_content .= $this->processSpecialConfigTemplate($domain['ssl_specialsettings'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; + } + if ($_vhost_content != '') { $vhost_content .= $_vhost_content; } - if (Settings::Get('system.default_vhostconf') != '') { + if (Settings::Get('system.default_vhostconf') != '' && ($ssl_vhost == false || ($ssl_vhost == true && Settings::Get('system.include_default_vhostconf') == 1))) { $vhost_content .= $this->processSpecialConfigTemplate(Settings::Get('system.default_vhostconf'), $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; } + + if (Settings::Get('system.default_sslvhostconf') != '' && $ssl_vhost == true) { + $vhost_content .= $this->processSpecialConfigTemplate(Settings::Get('system.default_sslvhostconf'), $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; + } } $vhost_content .= '' . "\n"; @@ -1209,7 +1213,7 @@ class Apache extends HttpConfigBase foreach ($statusCodes as $statusCode) { if (isset($row_diroptions['error' . $statusCode . 'path']) && $row_diroptions['error' . $statusCode . 'path'] != '') { $defhandler = $row_diroptions['error' . $statusCode . 'path']; - if (! \Froxlor\Validate\Form\Data::validateUrl($defhandler)) { + if (! \Froxlor\Validate\Validate::validateUrl($defhandler)) { if (substr($defhandler, 0, 1) != '"' && substr($defhandler, - 1, 1) != '"') { $defhandler = '"' . \Froxlor\FileDir::makeCorrectFile($defhandler) . '"'; } diff --git a/lib/Froxlor/Cron/Http/ConfigIO.php b/lib/Froxlor/Cron/Http/ConfigIO.php index a87e7a72..55002285 100644 --- a/lib/Froxlor/Cron/Http/ConfigIO.php +++ b/lib/Froxlor/Cron/Http/ConfigIO.php @@ -128,7 +128,7 @@ class ConfigIO // iterate through all subdirs, // look for vhost/diroption files // and delete them - foreach ($its as $fullFileName => $it) { + foreach ($its as $it) { if ($it->isFile() && preg_match($pattern, $it->getFilename())) { // remove file \Froxlor\FileDir::safe_exec('rm -f ' . escapeshellarg(\Froxlor\FileDir::makeCorrectFile($its->getPathname()))); @@ -191,7 +191,7 @@ class ConfigIO /** * don't do anything if the file does not exist */ - if (@file_exists($awstatsclean['fullentry'])) { + if (@file_exists($awstatsclean['fullentry']) && $awstatsclean['entry'] != '.' && $awstatsclean['entry'] != '..') { $awstatsclean['fh'] = fopen($awstatsclean['fullentry'], 'r'); $awstatsclean['headerRead'] = fgets($awstatsclean['fh'], strlen($awstatsclean['header']) + 1); fclose($awstatsclean['fh']); @@ -232,7 +232,7 @@ class ConfigIO // look for php-fcgi-starter files // and take immutable-flag away from them // so we can delete them :) - foreach ($its as $fullFileName => $it) { + foreach ($its as $it) { if ($it->isFile() && $it->getFilename() == 'php-fcgi-starter') { // set chattr -i \Froxlor\FileDir::removeImmutable($its->getPathname()); diff --git a/lib/Froxlor/Cron/Http/HttpConfigBase.php b/lib/Froxlor/Cron/Http/HttpConfigBase.php index 9e6daf20..eecbfeff 100644 --- a/lib/Froxlor/Cron/Http/HttpConfigBase.php +++ b/lib/Froxlor/Cron/Http/HttpConfigBase.php @@ -3,6 +3,7 @@ namespace Froxlor\Cron\Http; use Froxlor\Database\Database; use Froxlor\Settings; +use Froxlor\Cron\Http\Php\Fpm; /** * This file is part of the Froxlor project. @@ -27,6 +28,51 @@ use Froxlor\Settings; class HttpConfigBase { + public function init() + { + // if Let's Encrypt is activated, run it before regeneration of webserver configfiles + if (Settings::Get('system.leenabled') == 1) { + \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'Running Let\'s Encrypt cronjob prior to regenerating webserver config files'); + \Froxlor\Cron\Http\LetsEncrypt\AcmeSh::$no_inserttask = true; + \Froxlor\Cron\Http\LetsEncrypt\AcmeSh::run(true); + // set last run timestamp of cronjob + \Froxlor\System\Cronjob::updateLastRunOfCron('letsencrypt'); + } + } + + public function reload() + { + $called_class = get_called_class(); + if ((int) Settings::Get('phpfpm.enabled') == 1) { + // get all start/stop commands + $startstop_sel = Database::prepare("SELECT reload_cmd, config_dir FROM `" . TABLE_PANEL_FPMDAEMONS . "`"); + Database::pexecute($startstop_sel); + $restart_cmds = $startstop_sel->fetchAll(\PDO::FETCH_ASSOC); + // restart all php-fpm instances + foreach ($restart_cmds as $restart_cmd) { + // check whether the config dir is empty (no domains uses this daemon) + // so we need to create a dummy + $_conffiles = glob(\Froxlor\FileDir::makeCorrectFile($restart_cmd['config_dir'] . "/*.conf")); + if ($_conffiles === false || empty($_conffiles)) { + \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, $called_class . '::reload: fpm config directory "' . $restart_cmd['config_dir'] . '" is empty. Creating dummy.'); + Fpm::createDummyPool($restart_cmd['config_dir']); + } + \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, $called_class . '::reload: running ' . $restart_cmd['reload_cmd']); + \Froxlor\FileDir::safe_exec(escapeshellcmd($restart_cmd['reload_cmd'])); + } + } + \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, $called_class . '::reload: reloading ' . $called_class); + \Froxlor\FileDir::safe_exec(escapeshellcmd(Settings::Get('system.apachereload_command'))); + + /** + * nginx does not auto-spawn fcgi-processes + */ + if (Settings::Get('system.webserver') == "nginx" && Settings::Get('system.phpreload_command') != '' && (int) Settings::Get('phpfpm.enabled') == 0) { + \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, $called_class . '::reload: restarting php processes'); + \Froxlor\FileDir::safe_exec(Settings::Get('system.phpreload_command')); + } + } + /** * process special config as template, by substituting {VARIABLE} with the * respective value. @@ -87,7 +133,7 @@ class HttpConfigBase "); $ssldestport = Database::pexecute_first($ssldestport_stmt); - if ($ssldestport['port'] != '') { + if ($ssldestport && $ssldestport['port'] != '') { $_sslport = ":" . $ssldestport['port']; } diff --git a/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php b/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php index 07e1ec27..7ac838f4 100644 --- a/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php +++ b/lib/Froxlor/Cron/Http/LetsEncrypt/AcmeSh.php @@ -43,19 +43,26 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron private static $do_update = true; - public static function run() + public static $no_inserttask = false; + + public static function run($internal = false) { + if (! defined('CRON_IS_FORCED') && ! defined('CRON_DEBUG_FLAG') && $internal == false) { + // FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Let's Encrypt cronjob is combined with regeneration of webserver configuration files.\nFor debugging purposes you can use the --debug switch and/or the --force switch to run the cron manually."); + return 0; + } + self::checkInstall(); self::$apiserver = 'https://acme-v0' . \Froxlor\Settings::Get('system.leapiversion') . '.api.letsencrypt.org/directory'; - FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Updating Let's Encrypt certificates"); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Requesting/renewing Let's Encrypt certificates"); $certificates_stmt = Database::query(" SELECT domssl.`id`, domssl.`domainid`, - domssl.expirationdate, + domssl.`expirationdate`, domssl.`ssl_cert_file`, domssl.`ssl_key_file`, domssl.`ssl_ca_file`, @@ -174,7 +181,7 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron ); $froxlor_aliases = Settings::Get('system.froxloraliases'); - if (!empty($froxlor_aliases)) { + if (! empty($froxlor_aliases)) { $froxlor_aliases = explode(",", $froxlor_aliases); foreach ($froxlor_aliases as $falias) { if (\Froxlor\Validate\Validate::validateDomain(trim($falias))) { @@ -185,10 +192,12 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron // Only renew let's encrypt certificate if no broken ssl_redirect is enabled // - this temp. deactivation of the ssl-redirect is handled by the webserver-cronjob + $do_force = false; if ($cert_mode == 'renew') { - FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Creating certificate for " . $certrow['domain']); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updating certificate for " . $certrow['domain']); } else { - FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Updating certificate for " . $certrow['domain']); + $do_force = true; + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Creating certificate for " . $certrow['domain']); } $cronlog = FroxlorLogger::getInstanceOf(array( @@ -196,7 +205,7 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron 'adminsession' => 0 )); - self::runAcmeSh($certrow, $domains, $cert_mode, $cronlog, $changedetected); + self::runAcmeSh($certrow, $domains, $cert_mode, $cronlog, $changedetected, $do_force); } } @@ -214,20 +223,25 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron // Only renew let's encrypt certificate if no broken ssl_redirect is enabled if ($certrow['ssl_redirect'] != 2) { - if (! empty($certrow['ssl_cert_file'])) { + $do_force = false; + if (! empty($certrow['ssl_cert_file']) && ! empty($certrow['expirationdate'])) { $cert_mode = 'renew'; - $cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Updating certificate for " . $certrow['domain']); + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updating certificate for " . $certrow['domain']); + } else if (! empty($certrow['ssl_cert_file']) && empty($certrow['expirationdate'])) { + // domain changed (SAN or similar) + $do_force = true; + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']); } else { - $cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Creating certificate for " . $certrow['domain']); + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Creating certificate for " . $certrow['domain']); } - $cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . $certrow['domain']); + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . $certrow['domain']); $domains = array( $certrow['domain'] ); // add www. to SAN list if ($certrow['wwwserveralias'] == 1) { - $cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $certrow['domain']); + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $certrow['domain']); $domains[] = 'www.' . $certrow['domain']; } @@ -237,30 +251,33 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron )); $aliasdomains = $aliasdomains_stmt->fetchAll(\PDO::FETCH_ASSOC); foreach ($aliasdomains as $aliasdomain) { - $cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . $aliasdomain['domain']); + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: " . $aliasdomain['domain']); $domains[] = $aliasdomain['domain']; if ($aliasdomain['wwwserveralias'] == 1) { - $cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $aliasdomain['domain']); + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Adding SAN entry: www." . $aliasdomain['domain']); $domains[] = 'www.' . $aliasdomain['domain']; } } - self::runAcmeSh($certrow, $domains, $cert_mode, $cronlog, $changedetected); + self::runAcmeSh($certrow, $domains, $cert_mode, $cronlog, $changedetected, $do_force); } else { - $cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $certrow['domain'] . " due to an enabled ssl_redirect"); + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $certrow['domain'] . " due to an enabled ssl_redirect"); } } // If we have a change in a certificate, we need to update the webserver - configs // This is easiest done by just creating a new task ;) if ($changedetected) { - \Froxlor\System\Cronjob::inserttask(1); + if (self::$no_inserttask == false) { + \Froxlor\System\Cronjob::inserttask(1); + } + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Let's Encrypt certificates have been updated"); + } else { + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "No new certificates or certificates due for renewal found"); } - - FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Let's Encrypt certificates have been updated"); } - private static function runAcmeSh($certrow = array(), $domains = array(), $cert_mode = 'issue', &$cronlog = null, &$changedetected = 0) + private static function runAcmeSh($certrow = array(), $domains = array(), $cert_mode = 'issue', &$cronlog = null, &$changedetected = 0, $force = false) { if (! empty($domains)) { @@ -272,7 +289,7 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron $acmesh_cmd = self::$acmesh . " --auto-upgrade 0 --server " . self::$apiserver . " --" . $cert_mode . " -d " . implode(" -d ", $domains); if ($cert_mode == 'issue') { - $acmesh_cmd .= " -w " . \Froxlor\Froxlor::getInstallDir(); + $acmesh_cmd .= " -w " . Settings::Get('system.letsencryptchallengepath'); } if (Settings::Get('system.leecc') > 0) { $acmesh_cmd .= " --keylength ec-" . Settings::Get('system.leecc'); @@ -282,8 +299,16 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron if (Settings::Get('system.letsencryptreuseold') != '1') { $acmesh_cmd .= " --always-force-new-domain-key"; } + if (Settings::Get('system.letsencryptca') == 'testing') { + $acmesh_cmd .= " --staging"; + } + if ($force) { + $acmesh_cmd .= " --force"; + } $acme_result = \Froxlor\FileDir::safe_exec($acmesh_cmd); + // debug output of acme.sh run + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, implode("\n", $acme_result)); $return = array(); self::readCertificateToVar($certrow['domain'], $return); @@ -292,29 +317,33 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron $newcert = openssl_x509_parse($return['crt']); - // Store the new data - Database::pexecute(self::$updcert_stmt, array( - 'id' => $certrow['id'], - 'domainid' => $certrow['domainid'], - 'crt' => $return['crt'], - 'key' => $return['key'], - 'ca' => $return['chain'], - 'chain' => $return['chain'], - 'csr' => $return['csr'], - 'fullchain' => $return['fullchain'], - 'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t']) - )); - - if ($certrow['ssl_redirect'] == 3) { - Database::pexecute(self::$upddom_stmt, array( - 'domainid' => $certrow['domainid'] + if ($newcert) { + // Store the new data + Database::pexecute(self::$updcert_stmt, array( + 'id' => $certrow['id'], + 'domainid' => $certrow['domainid'], + 'crt' => $return['crt'], + 'key' => $return['key'], + 'ca' => $return['chain'], + 'chain' => $return['chain'], + 'csr' => $return['csr'], + 'fullchain' => $return['fullchain'], + 'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t']) )); - } - $cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Updated Let's Encrypt certificate for " . $certrow['domain']); - $changedetected = 1; + if ($certrow['ssl_redirect'] == 3) { + Database::pexecute(self::$upddom_stmt, array( + 'domainid' => $certrow['domainid'] + )); + } + + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updated Let's Encrypt certificate for " . $certrow['domain']); + $changedetected = 1; + } else { + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Got non-successful Let's Encrypt response for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result)); + } } else { - $cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not get Let's Encrypt certificate for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result)); + $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not get Let's Encrypt certificate for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result)); } } } @@ -328,18 +357,27 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron $certificate_folder = \Froxlor\FileDir::makeCorrectDir($certificate_folder); if (is_dir($certificate_folder)) { - $return['crt'] = file_get_contents(\Froxlor\FileDir::makeCorrectFile($certificate_folder . '/' . $domain . '.cer')); - $return['key'] = file_get_contents(\Froxlor\FileDir::makeCorrectFile($certificate_folder . '/' . $domain . '.key')); - $return['chain'] = file_get_contents(\Froxlor\FileDir::makeCorrectFile($certificate_folder . '/ca.cer')); - $return['fullchain'] = file_get_contents(\Froxlor\FileDir::makeCorrectFile($certificate_folder . '/fullchain.cer')); - $return['csr'] = file_get_contents(\Froxlor\FileDir::makeCorrectFile($certificate_folder . '/' . $domain . '.csr')); + foreach ([ + 'crt' => $domain . '.cer', + 'key' => $domain . '.key', + 'chain' => 'ca.cer', + 'fullchain' => 'fullchain.cer', + 'csr' => $domain . '.csr' + ] as $index => $sslfile) { + $ssl_file = \Froxlor\FileDir::makeCorrectFile($certificate_folder . '/' . $sslfile); + if (file_exists($ssl_file)) { + $return[$index] = file_get_contents($ssl_file); + } else { + $return[$index] = null; + } + } } } private static function checkInstall() { if (! file_exists(self::$acmesh)) { - FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Could not find acme.sh - installing it to /root/.acme.sh/"); + FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Could not find acme.sh - installing it to /root/.acme.sh/"); $return = false; \Froxlor\FileDir::safe_exec("wget -O - https://get.acme.sh | sh", $return, array( '|' @@ -350,6 +388,8 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron private static function checkUpgrade() { $acmesh_result = \Froxlor\FileDir::safe_exec(self::$acmesh . " --upgrade"); - FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "Checking for LetsEncrypt client upgrades before renewing certificates:\n" . implode("\n", $acmesh_result)); + // check for activated cron (which is installed automatically) but we don't need it + $acmesh_result2 = \Froxlor\FileDir::safe_exec(self::$acmesh . " --uninstall-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)); } } diff --git a/lib/Froxlor/Cron/Http/Lighttpd.php b/lib/Froxlor/Cron/Http/Lighttpd.php index 25dd6d95..4f94f0f8 100644 --- a/lib/Froxlor/Cron/Http/Lighttpd.php +++ b/lib/Froxlor/Cron/Http/Lighttpd.php @@ -3,7 +3,6 @@ namespace Froxlor\Cron\Http; use Froxlor\Database\Database; use Froxlor\Settings; -use Froxlor\Cron\Http\Php\Fpm; use Froxlor\Cron\Http\Php\PhpInterface; /** @@ -45,30 +44,6 @@ class Lighttpd extends HttpConfigBase */ private $deactivated = false; - public function reload() - { - if ((int) Settings::Get('phpfpm.enabled') == 1) { - // get all start/stop commands - $startstop_sel = Database::prepare("SELECT reload_cmd, config_dir FROM `" . TABLE_PANEL_FPMDAEMONS . "`"); - Database::pexecute($startstop_sel); - $restart_cmds = $startstop_sel->fetchAll(\PDO::FETCH_ASSOC); - // restart all php-fpm instances - foreach ($restart_cmds as $restart_cmd) { - // check whether the config dir is empty (no domains uses this daemon) - // so we need to create a dummy - $_conffiles = glob(\Froxlor\FileDir::makeCorrectFile($restart_cmd['config_dir'] . "/*.conf")); - if ($_conffiles === false || empty($_conffiles)) { - $this->logger->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'lighttpd::reload: fpm config directory "' . $restart_cmd['config_dir'] . '" is empty. Creating dummy.'); - Fpm::createDummyPool($restart_cmd['config_dir']); - } - $this->logger->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'lighttpd::reload: running ' . $restart_cmd['reload_cmd']); - \Froxlor\FileDir::safe_exec(escapeshellcmd($restart_cmd['reload_cmd'])); - } - } - $this->logger->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'lighttpd::reload: reloading lighttpd'); - \Froxlor\FileDir::safe_exec(escapeshellcmd(Settings::Get('system.apachereload_command'))); - } - public function createIpPort() { $result_ipsandports_stmt = Database::query("SELECT * FROM `" . TABLE_PANEL_IPSANDPORTS . "` ORDER BY `ip` ASC, `port` ASC"); @@ -200,7 +175,7 @@ class Lighttpd extends HttpConfigBase ); } - if ($row_ipsandports['specialsettings'] != '') { + if ($row_ipsandports['specialsettings'] != '' && ($row_ipsandports['ssl'] == '0' || ($row_ipsandports['ssl'] == '1' && Settings::Get('system.use_ssl') == '1' && $row_ipsandports['include_specialsettings'] == '1'))) { $this->lighttpd_data[$vhost_filename] .= $this->processSpecialConfigTemplate($row_ipsandports['specialsettings'], $domain, $row_ipsandports['ip'], $row_ipsandports['port'], $row_ipsandports['ssl'] == '1') . "\n"; } @@ -208,6 +183,11 @@ class Lighttpd extends HttpConfigBase } if ($row_ipsandports['ssl'] == '1') { + + if ($row_ipsandports['ssl_specialsettings'] != '') { + $this->lighttpd_data[$vhost_filename] .= $this->processSpecialConfigTemplate($row_ipsandports['ssl_specialsettings'], $domain, $row_ipsandports['ip'], $row_ipsandports['port'], $row_ipsandports['ssl'] == '1') . "\n"; + } + if ($row_ipsandports['ssl_cert_file'] == '') { $row_ipsandports['ssl_cert_file'] = Settings::Get('system.ssl_cert_file'); if (! file_exists($row_ipsandports['ssl_cert_file'])) { @@ -316,7 +296,7 @@ class Lighttpd extends HttpConfigBase } $defhandler = Settings::Get('defaultwebsrverrhandler.err404'); - if (! \Froxlor\Validate\Form\Data::validateUrl($defhandler)) { + if (! \Froxlor\Validate\Validate::validateUrl($defhandler)) { $defhandler = \Froxlor\FileDir::makeCorrectFile($defhandler); } $this->lighttpd_data[$vhost_filename] = 'server.error-handler-404 = "' . $defhandler . '"'; @@ -396,6 +376,7 @@ class Lighttpd extends HttpConfigBase protected function createLighttpdHosts($ipid, $ssl, $vhost_filename) { $domains = WebserverBase::getVhostsToCreate(); + $included_vhosts = array(); foreach ($domains as $domain) { if (is_dir(Settings::Get('system.apacheconf_vhost'))) { @@ -475,7 +456,7 @@ class Lighttpd extends HttpConfigBase 'domainid' => $domain['id'] )); - if ($ssldestport['port'] != '') { + if ($ssldestport && $ssldestport['port'] != '') { $_sslport = ":" . $ssldestport['port']; } @@ -536,17 +517,29 @@ class Lighttpd extends HttpConfigBase $vhost_content .= $this->getSslSettings($domain, $ssl_vhost); - if ($domain['specialsettings'] != "") { + if ($domain['specialsettings'] != '' && ($ssl_vhost == false || ($ssl_vhost == true && $domain['include_specialsettings'] == 1))) { $vhost_content .= $this->processSpecialConfigTemplate($domain['specialsettings'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; } - if ($ipandport['default_vhostconf_domain'] != '') { + if ($domain['ssl_specialsettings'] != '' && $ssl_vhost == true) { + $vhost_content .= $this->processSpecialConfigTemplate($domain['ssl_specialsettings'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; + } + + if ($ipandport['default_vhostconf_domain'] != '' && ($ssl_vhost == false || ($ssl_vhost == true && $ipandport['include_default_vhostconf_domain'] == '1'))) { $vhost_content .= $this->processSpecialConfigTemplate($ipandport['default_vhostconf_domain'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; } - if (Settings::Get('system.default_vhostconf') != '') { + if ($ipandport['ssl_default_vhostconf_domain'] != '' && $ssl_vhost == true) { + $vhost_content .= $this->processSpecialConfigTemplate($ipandport['ssl_default_vhostconf_domain'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; + } + + if (Settings::Get('system.default_vhostconf') != '' && ($ssl_vhost == false || ($ssl_vhost == true && Settings::Get('system.include_default_vhostconf') == 1))) { $vhost_content .= $this->processSpecialConfigTemplate(Settings::Get('system.default_vhostconf'), $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; } + + if (Settings::Get('system.default_sslvhostconf') != '' && $ssl_vhost == true) { + $vhost_content .= $this->processSpecialConfigTemplate(Settings::Get('system.default_sslvhostconf'), $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; + } } $vhost_content .= $this->getLogFiles($domain); } @@ -577,6 +570,8 @@ class Lighttpd extends HttpConfigBase if ($domain['ssl_cert_file'] != '') { + $ssl_cipher_list = ($domain['override_tls'] == '1' && ! empty($domain['ssl_cipher_list'])) ? $domain['ssl_cipher_list'] : Settings::Get('system.ssl_cipher_list'); + // ssl.engine only necessary once in the ip/port vhost (SERVER['socket'] condition) // $ssl_settings .= 'ssl.engine = "enable"' . "\n"; $ssl_settings .= 'ssl.use-compression = "disable"' . "\n"; @@ -590,7 +585,7 @@ class Lighttpd extends HttpConfigBase } $ssl_settings .= 'ssl.use-sslv2 = "disable"' . "\n"; $ssl_settings .= 'ssl.use-sslv3 = "disable"' . "\n"; - $ssl_settings .= 'ssl.cipher-list = "' . Settings::Get('system.ssl_cipher_list') . '"' . "\n"; + $ssl_settings .= 'ssl.cipher-list = "' . $ssl_cipher_list . '"' . "\n"; $ssl_settings .= 'ssl.honor-cipher-order = "enable"' . "\n"; $ssl_settings .= 'ssl.pemfile = "' . \Froxlor\FileDir::makeCorrectFile($domain['ssl_cert_file']) . '"' . "\n"; @@ -707,7 +702,7 @@ class Lighttpd extends HttpConfigBase if (! empty($row['error404path'])) { $defhandler = $row['error404path']; - if (! \Froxlor\Validate\Form\Data::validateUrl($defhandler)) { + if (! \Froxlor\Validate\Validate::validateUrl($defhandler)) { $defhandler = \Froxlor\FileDir::makeCorrectFile($domain['documentroot'] . '/' . $defhandler); } $error_string .= ' server.error-handler-404 = "' . $defhandler . '"' . "\n\n"; @@ -765,23 +760,21 @@ class Lighttpd extends HttpConfigBase )); while ($row_htpasswds = $result_stmt->fetch(\PDO::FETCH_ASSOC)) { - if ($auth_backend_loaded[$domain['ipandport']] != 'yes' && $auth_backend_loaded[$domain['ssl_ipandport']] != 'yes') { + if ($this->auth_backend_loaded[$domain['ipandport']] != 'yes' && $this->auth_backend_loaded[$domain['ssl_ipandport']] != 'yes') { $filename = $domain['customerid'] . '.htpasswd'; if ($this->auth_backend_loaded[$domain['ipandport']] != 'yes') { - $auth_backend_loaded[$domain['ipandport']] = 'yes'; + $this->auth_backend_loaded[$domain['ipandport']] = 'yes'; $diroption_text .= 'auth.backend = "htpasswd"' . "\n"; $diroption_text .= 'auth.backend.htpasswd.userfile = "' . \Froxlor\FileDir::makeCorrectFile(Settings::Get('system.apacheconf_htpasswddir') . '/' . $filename) . '"' . "\n"; $this->needed_htpasswds[$filename] = $row_htpasswds['username'] . ':' . $row_htpasswds['password'] . "\n"; $diroption_text .= 'auth.require = ( ' . "\n"; - $previous_domain_id = '1'; } elseif ($this->auth_backend_loaded[$domain['ssl_ipandport']] != 'yes') { - $auth_backend_loaded[$domain['ssl_ipandport']] = 'yes'; + $this->auth_backend_loaded[$domain['ssl_ipandport']] = 'yes'; $diroption_text .= 'auth.backend= "htpasswd"' . "\n"; $diroption_text .= 'auth.backend.htpasswd.userfile = "' . \Froxlor\FileDir::makeCorrectFile(Settings::Get('system.apacheconf_htpasswddir') . '/' . $filename) . '"' . "\n"; $this->needed_htpasswds[$filename] = $row_htpasswds['username'] . ':' . $row_htpasswds['password'] . "\n"; $diroption_text .= 'auth.require = ( ' . "\n"; - $previous_domain_id = '1'; } } diff --git a/lib/Froxlor/Cron/Http/Nginx.php b/lib/Froxlor/Cron/Http/Nginx.php index ff6f3669..84e69f8d 100644 --- a/lib/Froxlor/Cron/Http/Nginx.php +++ b/lib/Froxlor/Cron/Http/Nginx.php @@ -3,7 +3,6 @@ namespace Froxlor\Cron\Http; use Froxlor\Database\Database; use Froxlor\Settings; -use Froxlor\Cron\Http\Php\Fpm; use Froxlor\Cron\Http\Php\PhpInterface; /** @@ -55,39 +54,6 @@ class Nginx extends HttpConfigBase $this->nginx_server = $nginx_server; } - public function reload() - { - if ((int) Settings::Get('phpfpm.enabled') == 1) { - // get all start/stop commands - $startstop_sel = Database::prepare("SELECT reload_cmd, config_dir FROM `" . TABLE_PANEL_FPMDAEMONS . "`"); - Database::pexecute($startstop_sel); - $restart_cmds = $startstop_sel->fetchAll(\PDO::FETCH_ASSOC); - // restart all php-fpm instances - foreach ($restart_cmds as $restart_cmd) { - // check whether the config dir is empty (no domains uses this daemon) - // so we need to create a dummy - $_conffiles = glob(\Froxlor\FileDir::makeCorrectFile($restart_cmd['config_dir'] . "/*.conf")); - if ($_conffiles === false || empty($_conffiles)) { - \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'nginx::reload: fpm config directory "' . $restart_cmd['config_dir'] . '" is empty. Creating dummy.'); - Fpm::createDummyPool($restart_cmd['config_dir']); - } - \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'nginx::reload: running ' . $restart_cmd['reload_cmd']); - \Froxlor\FileDir::safe_exec(escapeshellcmd($restart_cmd['reload_cmd'])); - } - } - - \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'nginx::reload: reloading nginx'); - \Froxlor\FileDir::safe_exec(Settings::Get('system.apachereload_command')); - - /** - * nginx does not auto-spawn fcgi-processes - */ - if (Settings::Get('system.phpreload_command') != '' && (int) Settings::Get('phpfpm.enabled') == 0) { - \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, 'nginx::reload: restarting php processes'); - \Froxlor\FileDir::safe_exec(Settings::Get('system.phpreload_command')); - } - } - private function createLogformatEntry() { if (Settings::Get('system.logfiles_format') != '') { @@ -137,7 +103,7 @@ class Nginx extends HttpConfigBase foreach ($statusCodes as $statusCode) { if (Settings::Get('defaultwebsrverrhandler.err' . $statusCode) != '') { $defhandler = Settings::Get('defaultwebsrverrhandler.err' . $statusCode); - if (! \Froxlor\Validate\Form\Data::validateUrl($defhandler)) { + if (! \Froxlor\Validate\Validate::validateUrl($defhandler)) { $defhandler = \Froxlor\FileDir::makeCorrectFile($defhandler); } $this->nginx_data[$vhosts_filename] .= 'error_page ' . $statusCode . ' ' . $defhandler . ';' . "\n"; @@ -250,7 +216,7 @@ class Nginx extends HttpConfigBase $aliases = ""; $froxlor_aliases = Settings::Get('system.froxloraliases'); - if (!empty($froxlor_aliases)) { + if (! empty($froxlor_aliases)) { $froxlor_aliases = explode(",", $froxlor_aliases); foreach ($froxlor_aliases as $falias) { if (\Froxlor\Validate\Validate::validateDomain(trim($falias))) { @@ -278,7 +244,7 @@ class Nginx extends HttpConfigBase $is_redirect = false; } else { $_sslport = $this->checkAlternativeSslPort(); - $mypath = 'https://' . Settings::Get('system.hostname') . $_sslport . '/'; + $mypath = 'https://' . Settings::Get('system.hostname') . $_sslport; $this->nginx_data[$vhost_filename] .= "\t" . 'location / {' . "\n"; $this->nginx_data[$vhost_filename] .= "\t\t" . 'return 301 ' . $mypath . '$request_uri;' . "\n"; $this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n"; @@ -292,7 +258,7 @@ class Nginx extends HttpConfigBase $this->nginx_data[$vhost_filename] .= "\t" . '}' . "\n"; } - if ($row_ipsandports['specialsettings'] != '') { + if ($row_ipsandports['specialsettings'] != '' && ($row_ipsandports['ssl'] == '0' || ($row_ipsandports['ssl'] == '1' && Settings::Get('system.use_ssl') == '1' && $row_ipsandports['include_specialsettings'] == '1'))) { $this->nginx_data[$vhost_filename] .= $this->processSpecialConfigTemplate($row_ipsandports['specialsettings'], array( 'domain' => Settings::Get('system.hostname'), 'loginname' => Settings::Get('phpfpm.vhost_httpuser'), @@ -307,13 +273,21 @@ class Nginx extends HttpConfigBase if ($row_ipsandports['ssl'] == '1') { $row_ipsandports['domain'] = Settings::Get('system.hostname'); $this->nginx_data[$vhost_filename] .= $this->composeSslSettings($row_ipsandports); + if ($row_ipsandports['ssl_specialsettings'] != '') { + $this->nginx_data[$vhost_filename] .= $this->processSpecialConfigTemplate($row_ipsandports['ssl_specialsettings'], array( + 'domain' => Settings::Get('system.hostname'), + 'loginname' => Settings::Get('phpfpm.vhost_httpuser'), + 'documentroot' => $mypath, + 'customerroot' => $mypath + ), $row_ipsandports['ip'], $row_ipsandports['port'], $row_ipsandports['ssl'] == '1') . "\n"; + } } if (! $is_redirect) { $this->nginx_data[$vhost_filename] .= "\tlocation ~ \.php {\n"; $this->nginx_data[$vhost_filename] .= "\t\tfastcgi_split_path_info ^(.+\.php)(/.+)\$;\n"; $this->nginx_data[$vhost_filename] .= "\t\tinclude " . Settings::Get('nginx.fastcgiparams') . ";\n"; - $this->nginx_data[$vhost_filename] .= "\t\tfastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;\n"; + $this->nginx_data[$vhost_filename] .= "\t\tfastcgi_param SCRIPT_FILENAME \$request_filename;\n"; $this->nginx_data[$vhost_filename] .= "\t\tfastcgi_param PATH_INFO \$fastcgi_path_info;\n"; $this->nginx_data[$vhost_filename] .= "\t\ttry_files \$fastcgi_script_name =404;\n"; @@ -481,10 +455,12 @@ class Nginx extends HttpConfigBase $ipport = $domain['ip'] . ':' . $domain['port']; } - if ($ipandport['default_vhostconf_domain'] != '') { + if ($ipandport['default_vhostconf_domain'] != '' && ($ssl_vhost == false || ($ssl_vhost == true && $ipandport['include_default_vhostconf_domain'] == '1'))) { $_vhost_content .= $this->processSpecialConfigTemplate($ipandport['default_vhostconf_domain'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; } - + if ($ipandport['ssl_default_vhostconf_domain'] != '' && $ssl_vhost == true) { + $_vhost_content .= $this->processSpecialConfigTemplate($ipandport['ssl_default_vhostconf_domain'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; + } $http2 = $ssl_vhost == true && (isset($domain['http2']) && $domain['http2'] == '1' && Settings::Get('system.http2_support') == '1'); $vhost_content .= "\t" . 'listen ' . $ipport . ($ssl_vhost == true ? ' ssl' : '') . ($http2 == true ? ' http2' : '') . ';' . "\n"; @@ -510,7 +486,7 @@ class Nginx extends HttpConfigBase 'domainid' => $domain['id'] )); - if ($ssldestport['port'] != '') { + if ($ssldestport && $ssldestport['port'] != '') { $_sslport = ":" . $ssldestport['port']; } @@ -556,17 +532,25 @@ class Nginx extends HttpConfigBase $vhost_content .= isset($this->needed_htpasswds[$domain['id']]) ? $this->needed_htpasswds[$domain['id']] . "\n" : ''; - if ($domain['specialsettings'] != "") { + if ($domain['specialsettings'] != '' && ($ssl_vhost == false || ($ssl_vhost == true && $domain['include_specialsettings'] == 1))) { $vhost_content = $this->mergeVhostCustom($vhost_content, $this->processSpecialConfigTemplate($domain['specialsettings'], $domain, $domain['ip'], $domain['port'], $ssl_vhost)); } + if ($domain['ssl_specialsettings'] != '' && $ssl_vhost == true) { + $vhost_content .= $this->processSpecialConfigTemplate($domain['ssl_specialsettings'], $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; + } + if ($_vhost_content != '') { $vhost_content = $this->mergeVhostCustom($vhost_content, $_vhost_content); } - if (Settings::Get('system.default_vhostconf') != '') { + if (Settings::Get('system.default_vhostconf') != '' && ($ssl_vhost == false || ($ssl_vhost == true && Settings::Get('system.include_default_vhostconf') == 1))) { $vhost_content = $this->mergeVhostCustom($vhost_content, $this->processSpecialConfigTemplate(Settings::Get('system.default_vhostconf'), $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"); } + + if (Settings::Get('system.default_sslvhostconf') != '' && $ssl_vhost == true) { + $vhost_content .= $this->processSpecialConfigTemplate(Settings::Get('system.default_sslvhostconf'), $domain, $domain['ip'], $domain['port'], $ssl_vhost) . "\n"; + } } } $vhost_content .= "\n}\n\n"; @@ -574,26 +558,38 @@ class Nginx extends HttpConfigBase return $vhost_content; } + private function cleanVhostStruct($vhost = null) + { + // Remove windows linebreaks + $vhost = str_replace("\r", "\n", $vhost); + // Break blocks into lines + $vhost = str_replace(array( + "{", + "}" + ), array( + " {\n", + "\n}" + ), $vhost); + // Break into array items + $vhost = explode("\n", preg_replace('/[ \t]+/', ' ', trim(preg_replace('/\t+/', '', $vhost)))); + // Remove empty lines + $vhost = array_filter($vhost, function ($a) { + return preg_match("#\S#", $a); + }); + + // remove unnecessary whitespaces + $vhost = array_map("trim", $vhost); + // re-number array keys + $vhost = array_values($vhost); + return $vhost; + } + protected function mergeVhostCustom($vhost_frx, $vhost_usr) { // Clean froxlor defined settings - $vhost_frx = explode("\n", preg_replace('/[ \t]+/', ' ', trim(preg_replace('/\t+/', '', $vhost_frx)))); // Break into array items - $vhost_frx = array_map("trim", $vhost_frx); // remove unnecessary whitespaces - + $vhost_frx = $this->cleanVhostStruct($vhost_frx); // Clean user defined settings - $vhost_usr = str_replace("\r", "\n", $vhost_usr); // Remove windows linebreaks - $vhost_usr = str_replace(array( - "{ ", - " }" - ), array( - "{\n", - "\n}" - ), $vhost_usr); // Break blocks into lines - $vhost_usr = explode("\n", preg_replace('/[ \t]+/', ' ', trim(preg_replace('/\t+/', '', $vhost_usr)))); // Break into array items - // Remove empty lines - $vhost_usr = array_filter($vhost_usr, function ($a) { - return preg_match("#\S#", $a); - }); + $vhost_usr = $this->cleanVhostStruct($vhost_usr); // Cycle through the user defined settings $currentBlock = array(); @@ -682,10 +678,14 @@ class Nginx extends HttpConfigBase if (! file_exists($domain_or_ip['ssl_cert_file'])) { \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_ERR, $domain_or_ip['domain'] . ' :: certificate file "' . $domain_or_ip['ssl_cert_file'] . '" does not exist! Cannot create ssl-directives'); } else { + + $ssl_protocols = (isset($domain_or_ip['override_tls']) && $domain_or_ip['override_tls'] == '1' && ! empty($domain_or_ip['ssl_protocols'])) ? $domain_or_ip['ssl_protocols'] : Settings::Get('system.ssl_protocols'); + $ssl_cipher_list = (isset($domain_or_ip['override_tls']) && $domain_or_ip['override_tls'] == '1' && ! empty($domain_or_ip['ssl_cipher_list'])) ? $domain_or_ip['ssl_cipher_list'] : Settings::Get('system.ssl_cipher_list'); + // obsolete: ssl on now belongs to the listen block as 'ssl' at the end // $sslsettings .= "\t" . 'ssl on;' . "\n"; - $sslsettings .= "\t" . 'ssl_protocols ' . str_replace(",", " ", Settings::Get('system.ssl_protocols')) . ';' . "\n"; - $sslsettings .= "\t" . 'ssl_ciphers ' . Settings::Get('system.ssl_cipher_list') . ';' . "\n"; + $sslsettings .= "\t" . 'ssl_protocols ' . str_replace(",", " ", $ssl_protocols) . ';' . "\n"; + $sslsettings .= "\t" . 'ssl_ciphers ' . $ssl_cipher_list . ';' . "\n"; if (! empty(Settings::Get('system.dhparams_file'))) { $dhparams = \Froxlor\FileDir::makeCorrectFile(Settings::Get('system.dhparams_file')); if (! file_exists($dhparams)) { @@ -693,8 +693,13 @@ class Nginx extends HttpConfigBase } $sslsettings .= 'ssl_dhparam ' . $dhparams . ';' . "\n"; } - $sslsettings .= "\t" . 'ssl_ecdh_curve secp384r1;' . "\n"; + // When <1.11.0: Defaults to prime256v1, similar to first curve recommendation by Mozilla. + // (When specifyng just one, there's no fallback when specific curve is not supported by client.) + // When >1.11.0: Defaults to auto, using recommended curves provided by OpenSSL. + // see https://github.com/Froxlor/Froxlor/issues/652 + // $sslsettings .= "\t" . 'ssl_ecdh_curve secp384r1;' . "\n"; $sslsettings .= "\t" . 'ssl_prefer_server_ciphers on;' . "\n"; + $sslsettings .= "\t" . 'ssl_session_cache shared:SSL:10m;' . "\n"; $sslsettings .= "\t" . 'ssl_certificate ' . \Froxlor\FileDir::makeCorrectFile($domain_or_ip['ssl_cert_file']) . ';' . "\n"; if ($domain_or_ip['ssl_key_file'] != '') { @@ -745,7 +750,7 @@ class Nginx extends HttpConfigBase while ($row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) { if (! empty($row['error404path'])) { $defhandler = $row['error404path']; - if (! \Froxlor\Validate\Form\Data::validateUrl($defhandler)) { + if (! \Froxlor\Validate\Validate::validateUrl($defhandler)) { $defhandler = \Froxlor\FileDir::makeCorrectFile($defhandler); } $path_options .= "\t" . 'error_page 404 ' . $defhandler . ';' . "\n"; @@ -753,7 +758,7 @@ class Nginx extends HttpConfigBase if (! empty($row['error403path'])) { $defhandler = $row['error403path']; - if (! \Froxlor\Validate\Form\Data::validateUrl($defhandler)) { + if (! \Froxlor\Validate\Validate::validateUrl($defhandler)) { $defhandler = \Froxlor\FileDir::makeCorrectFile($defhandler); } $path_options .= "\t" . 'error_page 403 ' . $defhandler . ';' . "\n"; @@ -761,7 +766,7 @@ class Nginx extends HttpConfigBase if (! empty($row['error500path'])) { $defhandler = $row['error500path']; - if (! \Froxlor\Validate\Form\Data::validateUrl($defhandler)) { + if (! \Froxlor\Validate\Validate::validateUrl($defhandler)) { $defhandler = \Froxlor\FileDir::makeCorrectFile($defhandler); } $path_options .= "\t" . 'error_page 500 502 503 504 ' . $defhandler . ';' . "\n"; @@ -911,6 +916,7 @@ class Nginx extends HttpConfigBase $path = \Froxlor\FileDir::makeCorrectDir(substr($row_htpasswds['path'], strlen($domain['documentroot']) - 1)); } else { // if the website contents is located in a subdirectory of the user + $matches = array(); preg_match('/^([\/[:print:]]*\/)([[:print:]\/]+){1}$/i', $row_htpasswds['path'], $matches); $path = \Froxlor\FileDir::makeCorrectDir(substr($row_htpasswds['path'], strlen($matches[1]) - 1)); } @@ -951,7 +957,7 @@ class Nginx extends HttpConfigBase $phpopts .= "\tlocation @php {\n"; $phpopts .= "\t\tfastcgi_split_path_info ^(.+\.php)(/.+)\$;\n"; $phpopts .= "\t\tinclude " . Settings::Get('nginx.fastcgiparams') . ";\n"; - $phpopts .= "\t\tfastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;\n"; + $phpopts .= "\t\tfastcgi_param SCRIPT_FILENAME \$request_filename;\n"; $phpopts .= "\t\tfastcgi_param PATH_INFO \$fastcgi_path_info;\n"; $phpopts .= "\t\ttry_files \$fastcgi_script_name =404;\n"; $phpopts .= "\t\tfastcgi_pass " . Settings::Get('system.nginx_php_backend') . ";\n"; diff --git a/lib/Froxlor/Cron/Http/NginxFcgi.php b/lib/Froxlor/Cron/Http/NginxFcgi.php index 83da6cfe..b2031613 100644 --- a/lib/Froxlor/Cron/Http/NginxFcgi.php +++ b/lib/Froxlor/Cron/Http/NginxFcgi.php @@ -35,10 +35,10 @@ class NginxFcgi extends Nginx $php_options_text .= "\t" . '}' . "\n\n"; $php_options_text .= "\t" . 'location @php {' . "\n"; - $php_options_text .= "\t\t" . 'try_files $1 = 404;' . "\n\n"; + $php_options_text .= "\t\t" . 'try_files $1 =404;' . "\n\n"; $php_options_text .= "\t\t" . 'include ' . Settings::Get('nginx.fastcgiparams') . ";\n"; $php_options_text .= "\t\t" . 'fastcgi_split_path_info ^(.+\.php)(/.+)\$;' . "\n"; - $php_options_text .= "\t\t" . 'fastcgi_param SCRIPT_FILENAME $document_root$1;' . "\n"; + $php_options_text .= "\t\t" . 'fastcgi_param SCRIPT_FILENAME $request_filename;' . "\n"; $php_options_text .= "\t\t" . 'fastcgi_param PATH_INFO $2;' . "\n"; if ($domain['ssl'] == '1' && $ssl_vhost) { $php_options_text .= "\t\t" . 'fastcgi_param HTTPS on;' . "\n"; diff --git a/lib/Froxlor/Cron/Http/WebserverBase.php b/lib/Froxlor/Cron/Http/WebserverBase.php index fa958c05..fbca2677 100644 --- a/lib/Froxlor/Cron/Http/WebserverBase.php +++ b/lib/Froxlor/Cron/Http/WebserverBase.php @@ -36,9 +36,7 @@ class WebserverBase `d`.`phpsettingid`, `c`.`adminid`, `c`.`guid`, `c`.`email`, `c`.`documentroot` AS `customerroot`, `c`.`deactivated`, `c`.`phpenabled` AS `phpenabled_customer`, - `d`.`phpenabled` AS `phpenabled_vhost`, - `d`.`mod_fcgid_starter`,`d`.`mod_fcgid_maxrequests`, - `d`.`ocsp_stapling` + `d`.`phpenabled` AS `phpenabled_vhost` FROM `" . TABLE_PANEL_DOMAINS . "` `d` LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`) diff --git a/lib/Froxlor/Cron/MasterCron.php b/lib/Froxlor/Cron/MasterCron.php index 48ca32ee..0c4c88e4 100644 --- a/lib/Froxlor/Cron/MasterCron.php +++ b/lib/Froxlor/Cron/MasterCron.php @@ -44,8 +44,9 @@ class MasterCron extends \Froxlor\Cron\FroxlorCron echo "Below are possible parameters for this file\n\n"; echo "--[cronname]\t\tincludes the given cron-file\n"; echo "--force\t\t\tforces re-generating of config-files (webserver, nameserver, etc.)\n"; + echo "--run-task\t\trun a specific task [1 = re-generate configs, 4 = re-generate dns zones, 10 = re-set quotas, 99 = re-create cron.d-file]\n"; echo "--debug\t\t\toutput debug information about what is going on to STDOUT.\n"; - echo "--no-fork\t\t\tdo not fork to backkground (traffic cron only).\n\n"; + echo "--no-fork\t\tdo not fork to backkground (traffic cron only).\n\n"; } /** @@ -70,10 +71,19 @@ class MasterCron extends \Froxlor\Cron\FroxlorCron // also regenerate cron.d-file \Froxlor\System\Cronjob::inserttask('99'); array_push($jobs_to_run, 'tasks'); + define('CRON_IS_FORCED', 1); } elseif (strtolower($argv[$x]) == '--debug') { define('CRON_DEBUG_FLAG', 1); } elseif (strtolower($argv[$x]) == '--no-fork') { define('CRON_NOFORK_FLAG', 1); + } elseif (strtolower($argv[$x]) == '--run-task') { + if (isset($argv[$x+1]) && in_array($argv[$x+1], [1,4,10,99])) { + \Froxlor\System\Cronjob::inserttask($argv[$x+1]); + array_push($jobs_to_run, 'tasks'); + } else { + echo "Invalid argument for --run-task\n"; + exit; + } } elseif (substr(strtolower($argv[$x]), 0, 2) == '--') { // --[cronname] if (strlen($argv[$x]) > 3) { @@ -90,34 +100,18 @@ class MasterCron extends \Froxlor\Cron\FroxlorCron $tasks_cnt_stmt = \Froxlor\Database\Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`"); $tasks_cnt = $tasks_cnt_stmt->fetch(\PDO::FETCH_ASSOC); - + // do we have anything to include? if (count($jobs_to_run) > 0) { // include all jobs we want to execute foreach ($jobs_to_run as $cron) { - self::updateLastRunOfCron($cron); + \Froxlor\System\Cronjob::updateLastRunOfCron($cron); $cronfile = self::getCronModule($cron); if ($cronfile && class_exists($cronfile)) { $cronfile::run(); } } - - if ($tasks_cnt['jobcnt'] > 0) { - if (\Froxlor\Settings::Get('system.nssextrausers') == 1) { - \Froxlor\Cron\System\Extrausers::generateFiles(self::$cronlog); - } - - // clear NSCD cache if using fcgid or fpm, #1570 - if (\Froxlor\Settings::Get('system.mod_fcgid') == 1 || (int) \Froxlor\Settings::Get('phpfpm.enabled') == 1) { - $false_val = false; - \Froxlor\FileDir::safe_exec('nscd -i passwd 1> /dev/null', $false_val, array( - '>' - )); - \Froxlor\FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, array( - '>' - )); - } - } + self::refreshUsers($tasks_cnt['jobcnt']); } /** @@ -132,6 +126,26 @@ class MasterCron extends \Froxlor\Cron\FroxlorCron self::shutdown(); } + private static function refreshUsers($jobcount = 0) + { + if ($jobcount > 0) { + if (\Froxlor\Settings::Get('system.nssextrausers') == 1) { + \Froxlor\Cron\System\Extrausers::generateFiles(self::$cronlog); + } + + // clear NSCD cache if using fcgid or fpm, #1570 - not needed for nss-extrausers + if ((\Froxlor\Settings::Get('system.mod_fcgid') == 1 || (int) \Froxlor\Settings::Get('phpfpm.enabled') == 1) && \Froxlor\Settings::Get('system.nssextrausers') == 0) { + $false_val = false; + \Froxlor\FileDir::safe_exec('nscd -i passwd 1> /dev/null', $false_val, array( + '>' + )); + \Froxlor\FileDir::safe_exec('nscd -i group 1> /dev/null', $false_val, array( + '>' + )); + } + } + } + private static function init() { if (@php_sapi_name() != 'cli' && @php_sapi_name() != 'cgi' && @php_sapi_name() != 'cgi-fcgi') { @@ -335,16 +349,6 @@ class MasterCron extends \Froxlor\Cron\FroxlorCron } } - private static function updateLastRunOfCron($cronname) - { - $upd_stmt = Database::prepare(" - UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET `lastrun` = UNIX_TIMESTAMP() WHERE `cronfile` = :cron; - "); - Database::pexecute($upd_stmt, array( - 'cron' => $cronname - )); - } - private static function getCronModule($cronname) { $upd_stmt = Database::prepare(" diff --git a/lib/Froxlor/Cron/System/MailboxsizeCron.php b/lib/Froxlor/Cron/System/MailboxsizeCron.php index 154b5685..d35df4ef 100644 --- a/lib/Froxlor/Cron/System/MailboxsizeCron.php +++ b/lib/Froxlor/Cron/System/MailboxsizeCron.php @@ -38,26 +38,45 @@ class MailboxsizeCron extends \Froxlor\Cron\FroxlorCron $_maildir = \Froxlor\FileDir::makeCorrectDir($maildir['maildirpath']); if (file_exists($_maildir) && is_dir($_maildir)) { - // mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part - $return = false; - $back = \Froxlor\FileDir::safe_exec('du -sk ' . escapeshellarg($_maildir), $return, array( - '|', - '&', - '`', - '$', - '~', - '?' - )); - foreach ($back as $backrow) { - $emailusage = explode(' ', $backrow); + $maildirsize = \Froxlor\FileDir::makeCorrectFile($_maildir . '/maildirsize'); + + // When quota is enabled and maildirsize file exists, use that to calculate size + if (\Froxlor\Settings::Get('system.mail_quota_enabled') == 1 && file_exists($maildirsize)) { + \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'found maildirsize file in ' . $_maildir); + $file = file($maildirsize, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + // Remove header + array_shift($file); + $emailusage = 0; + // Sum up all the changes (line 2 -> end) + foreach ($file as $line) { + $parts = explode(' ', $line); + if (!empty($parts[0])) { + $emailusage += floatval($parts[0]); + } + } + } else { + // if quota is disabled or maildirsize file does not exist, compute with du + // mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part + $return = false; + $back = \Froxlor\FileDir::safe_exec('du -sk ' . escapeshellarg($_maildir), $return, array( + '|', + '&', + '`', + '$', + '~', + '?' + )); + foreach ($back as $backrow) { + $emailusage = explode(' ', $backrow); + } + $emailusage = floatval($emailusage['0']); + + // as freebsd does not have the -b flag for 'du' which gives + // the size in bytes, we use "-sk" for all and calculate from KiB + $emailusage *= 1024; + + unset($back); } - $emailusage = floatval($emailusage['0']); - - // as freebsd does not have the -b flag for 'du' which gives - // the size in bytes, we use "-sk" for all and calculate from KiB - $emailusage *= 1024; - - unset($back); \Froxlor\Database\Database::pexecute($upd_stmt, array( 'size' => $emailusage, 'id' => $maildir['id'] diff --git a/lib/Froxlor/Cron/System/TasksCron.php b/lib/Froxlor/Cron/System/TasksCron.php index 6cf0ea7e..b340fea1 100644 --- a/lib/Froxlor/Cron/System/TasksCron.php +++ b/lib/Froxlor/Cron/System/TasksCron.php @@ -30,8 +30,9 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron */ self::$cronlog->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_INFO, "TasksCron: Searching for tasks to do"); // no type 99 (regenerate cron.d-file) and no type 20 (customer backup) + // order by type descending to re-create bind and then webserver at the end $result_tasks_stmt = Database::query(" - SELECT `id`, `type`, `data` FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` <> '99' AND `type` <> '20' ORDER BY `id` ASC + SELECT `id`, `type`, `data` FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` <> '99' AND `type` <> '20' ORDER BY `type` DESC, `id` ASC "); $num_results = Database::num_rows(); $resultIDs = array(); @@ -92,6 +93,12 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron */ \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_NOTICE, "Removing PowerDNS entries for domain " . $row['data']['domain']); \Froxlor\Dns\PowerDNS::cleanDomainZone($row['data']['domain']); + } elseif ($row['type'] == '12') { + /** + * TYPE=12 domain has been deleted, remove from acme.sh/let's encrypt directory if used + */ + \Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_NOTICE, "Removing Let's Encrypt entries for domain " . $row['data']['domain']); + \Froxlor\Domain\Domain::doLetsEncryptCleanUp($row['data']['domain']); } } @@ -102,7 +109,7 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron $where[] = "`id` = :id_" . (int) $id; $where_data['id_' . $id] = $id; } - $where = implode($where, ' OR '); + $where = implode(' OR ', $where); $del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE " . $where); Database::pexecute($del_stmt, $where_data); unset($resultIDs); @@ -114,10 +121,6 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron private static function rebuildWebserverConfigs() { - // get configuration-I/O object - $configio = new \Froxlor\Cron\Http\ConfigIO(); - // clean up old configs - $configio->cleanUp(); if (Settings::Get('system.webserver') == "apache2") { $websrv = '\\Froxlor\\Cron\\Http\\Apache'; @@ -136,9 +139,15 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron } } + // get configuration-I/O object + $configio = new \Froxlor\Cron\Http\ConfigIO(); + // get webserver object $webserver = new $websrv(); if (isset($webserver)) { + $webserver->init(); + // clean up old configs + $configio->cleanUp(); $webserver->createIpPort(); $webserver->createVirtualHosts(); $webserver->createFileDirOptions(); @@ -231,8 +240,8 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron Extrausers::generateFiles($extrausers_log); } - // clear NSCD cache if using fcgid or fpm, #1570 - if (Settings::Get('system.mod_fcgid') == 1 || (int) Settings::Get('phpfpm.enabled') == 1) { + // clear NSCD cache if using fcgid or fpm, #1570 - not needed for nss-extrausers + if ((Settings::Get('system.mod_fcgid') == 1 || (int) Settings::Get('phpfpm.enabled') == 1) && Settings::Get('system.nssextrausers') == 0) { $false_val = false; \Froxlor\FileDir::safe_exec('nscd -i passwd 1> /dev/null', $false_val, array( '>' diff --git a/lib/Froxlor/Database/Database.php b/lib/Froxlor/Database/Database.php index 466a948e..d0791148 100644 --- a/lib/Froxlor/Database/Database.php +++ b/lib/Froxlor/Database/Database.php @@ -183,6 +183,21 @@ class Database return $return; } + /** + * return number of characters that are allowed to use as username + * + * @return int + */ + 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; + } + return $mysql_max; + } + /** * let's us interact with the PDO-Object by using static * call like "Database::function()" diff --git a/lib/Froxlor/Database/Manager/DbManagerMySQL.php b/lib/Froxlor/Database/Manager/DbManagerMySQL.php index e98ea86b..c130ffcc 100644 --- a/lib/Froxlor/Database/Manager/DbManagerMySQL.php +++ b/lib/Froxlor/Database/Manager/DbManagerMySQL.php @@ -82,9 +82,11 @@ class DbManagerMySQL if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '8.0.11', '>=')) { // create user $stmt = Database::prepare(" - CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED BY 'password' + CREATE USER '" . $username . "'@'" . $access_host . "' IDENTIFIED BY :password "); - Database::pexecute($stmt); + Database::pexecute($stmt, array( + "password" => $password + )); // grant privileges $stmt = Database::prepare(" GRANT ALL ON `" . $username . "`.* TO :username@:host @@ -96,29 +98,31 @@ class DbManagerMySQL } else { // grant privileges $stmt = Database::prepare(" - GRANT ALL PRIVILEGES ON `" . $username . "`.* TO :username@:host IDENTIFIED BY 'password' + GRANT ALL PRIVILEGES ON `" . $username . "`.* TO :username@:host IDENTIFIED BY :password "); Database::pexecute($stmt, array( "username" => $username, - "host" => $access_host + "host" => $access_host, + "password" => $password )); } - } - // set passoword - if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.6', '<')) { - if ($p_encrypted) { - $stmt = Database::prepare("SET PASSWORD FOR :username@:host = :password"); - } else { - $stmt = Database::prepare("SET PASSWORD FOR :username@:host = PASSWORD(:password)"); - } } else { - $stmt = Database::prepare("ALTER USER :username@:host IDENTIFIED BY :password"); + // set passoword + if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.6', '<')) { + if ($p_encrypted) { + $stmt = Database::prepare("SET PASSWORD FOR :username@:host = :password"); + } else { + $stmt = Database::prepare("SET PASSWORD FOR :username@:host = PASSWORD(:password)"); + } + } else { + $stmt = Database::prepare("ALTER USER :username@:host IDENTIFIED BY :password"); + } + Database::pexecute($stmt, array( + "username" => $username, + "host" => $access_host, + "password" => $password + )); } - Database::pexecute($stmt, array( - "username" => $username, - "host" => $access_host, - "password" => $password - )); } /** @@ -142,7 +146,11 @@ class DbManagerMySQL )); // as of MySQL 5.0.2 this also revokes privileges. (requires MySQL 4.1.2+) - $drop_stmt = Database::prepare("DROP USER IF EXISTS :dbname@:host"); + if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.0', '<')) { + $drop_stmt = Database::prepare("DROP USER :dbname@:host"); + } else { + $drop_stmt = Database::prepare("DROP USER IF EXISTS :dbname@:host"); + } while ($host = $host_res_stmt->fetch(\PDO::FETCH_ASSOC)) { Database::pexecute($drop_stmt, array( 'dbname' => $dbname, @@ -150,6 +158,7 @@ class DbManagerMySQL ), false); } + $drop_stmt = Database::prepare("DROP DATABASE IF EXISTS `" . $dbname . "`"); Database::pexecute($drop_stmt); } @@ -168,7 +177,11 @@ class DbManagerMySQL Database::pexecute($stmt); } // as of MySQL 5.0.2 this also revokes privileges. (requires MySQL 4.1.2+) - $stmt = Database::prepare("DROP USER :username@:host"); + if (version_compare(Database::getAttribute(\PDO::ATTR_SERVER_VERSION), '5.7.0', '<')) { + $stmt = Database::prepare("DROP USER :username@:host"); + } else { + $stmt = Database::prepare("DROP USER IF EXISTS :username@:host"); + } Database::pexecute($stmt, array( "username" => $username, "host" => $host diff --git a/lib/Froxlor/Dns/Dns.php b/lib/Froxlor/Dns/Dns.php index cfc77e93..2bf9c371 100644 --- a/lib/Froxlor/Dns/Dns.php +++ b/lib/Froxlor/Dns/Dns.php @@ -130,6 +130,12 @@ class Dns } } + // additional required records for CAA if activated + if (Settings::Get('system.dns_createcaaentry') && Settings::Get('system.use_ssl') == "1" && !empty($domain['p_ssl_ipandports'])) { + // check for CAA content later + self::addRequiredEntry('@CAA@', 'CAA', $required_entries); + } + // additional required records for SPF and DKIM if activated if ($domain['isemaildomain'] == '1') { if (Settings::Get('spf.use_spf') == '1') { @@ -150,6 +156,10 @@ class Dns if (array_key_exists($entry['type'], $required_entries) && array_key_exists(md5($entry['record']), $required_entries[$entry['type']])) { unset($required_entries[$entry['type']][md5($entry['record'])]); } + if (Settings::Get('system.dns_createcaaentry') == '1' && $entry['type'] == 'CAA' && strtolower(substr($entry['content'], 0, 7)) == '"v=caa1') { + // unset special CAA required-entry + unset($required_entries[$entry['type']][md5("@CAA@")]); + } if (Settings::Get('spf.use_spf') == '1' && $entry['type'] == 'TXT' && $entry['record'] == '@' && strtolower(substr($entry['content'], 0, 7)) == '"v=spf1') { // unset special spf required-entry unset($required_entries[$entry['type']][md5("@SPF@")]); @@ -278,6 +288,31 @@ class Dns } } } + + // CAA + if (array_key_exists("CAA", $required_entries)) { + foreach ($required_entries as $type => $records) { + if ($type == 'CAA') { + foreach ($records as $record) { + if ($record == '@CAA@') { + $caa_entries = explode(PHP_EOL, Settings::Get('caa.caa_entry')); + if ($domain['letsencrypt'] == 1) { + $le_entry = $domain['iswildcarddomain'] == '1' ? '0 issuewild "letsencrypt.org"' : '0 issue "letsencrypt.org"'; + array_push($caa_entries, $le_entry); + } + + foreach ($caa_entries as $entry) { + $zonerecords[] = new DnsEntry('@', 'CAA', $entry); + // additional required records by subdomain setting + if ($domain['wwwserveralias'] == '1') { + $zonerecords[] = new DnsEntry('www', 'CAA', $entry); + } + } + } + } + } + } + } } if (empty($primary_ns)) { diff --git a/lib/Froxlor/Domain/Domain.php b/lib/Froxlor/Domain/Domain.php index b952e467..bb0d2d7f 100644 --- a/lib/Froxlor/Domain/Domain.php +++ b/lib/Froxlor/Domain/Domain.php @@ -291,6 +291,30 @@ class Domain } } + public static function doLetsEncryptCleanUp($domainname = null) + { + // @ see \Froxlor\Cron\Http\LetsEncrypt\AcmeSh.php + $acmesh = "/root/.acme.sh/acme.sh"; + if (file_exists($acmesh)) { + $certificate_folder = dirname($acmesh) . "/" . $domainname; + if (\Froxlor\Settings::Get('system.leecc') > 0) { + $certificate_folder .= "_ecc"; + } + $certificate_folder = \Froxlor\FileDir::makeCorrectDir($certificate_folder); + if (file_exists($certificate_folder)) { + $params = " --remove -d " . $domainname; + if (\Froxlor\Settings::Get('system.leecc') > 0) { + $params .= " --ecc"; + } + // run remove command + \Froxlor\FileDir::safe_exec($acmesh . $params); + // remove certificates directory + @unlink($certificate_folder); + } + } + return true; + } + /** * checks give path for security issues * and returns a string that can be appended diff --git a/lib/Froxlor/FileDir.php b/lib/Froxlor/FileDir.php index 700ef2f7..d7a5e55c 100644 --- a/lib/Froxlor/FileDir.php +++ b/lib/Froxlor/FileDir.php @@ -217,7 +217,7 @@ class FileDir 'ADMIN_EMAIL' => $template['admin_email'] ); - // @fixme replaceVariables + // replaceVariables $htmlcontent = PhpHelper::replaceVariables($template['value'], $replace_arr); $indexhtmlpath = self::makeCorrectFile($destination . '/index.' . Settings::Get('system.index_file_extension')); $index_html_handler = fopen($indexhtmlpath, 'w'); diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 99934a6d..38126ef0 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -7,10 +7,10 @@ final class Froxlor { // Main version variable - const VERSION = '0.10.0-rc1'; + const VERSION = '0.10.3'; // Database version (YYYYMMDDC where C is a daily counter) - const DBVERSION = '201904250'; + const DBVERSION = '201910200'; // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; diff --git a/lib/Froxlor/FroxlorLogger.php b/lib/Froxlor/FroxlorLogger.php index 247c76f2..e8cbc84d 100644 --- a/lib/Froxlor/FroxlorLogger.php +++ b/lib/Froxlor/FroxlorLogger.php @@ -40,6 +40,13 @@ class FroxlorLogger */ private static $userinfo = array(); + /** + * whether the logger object has already been initialized + * + * @var bool + */ + private static $is_initialized = false; + const USR_ACTION = '10'; const RES_ACTION = '20'; @@ -72,19 +79,25 @@ class FroxlorLogger } } - foreach (self::$logtypes as $logger) { + if (self::$is_initialized == false) { + foreach (self::$logtypes as $logger) { - switch ($logger) { - case 'syslog': - self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG)); - break; - case 'file': - self::$ml->pushHandler(new StreamHandler(Settings::Get('logger.logfile'), Logger::DEBUG)); - break; - case 'mysql': - self::$ml->pushHandler(new MysqlHandler(Logger::DEBUG)); - break; + switch ($logger) { + case 'syslog': + self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG)); + break; + case 'file': + if (empty(Settings::Get('logger.logfile')) || ! is_writeable(Settings::Get('logger.logfile'))) { + Settings::Set('logger.logfile', '/tmp/froxlor.log'); + } + self::$ml->pushHandler(new StreamHandler(Settings::Get('logger.logfile'), Logger::DEBUG)); + break; + case 'mysql': + self::$ml->pushHandler(new MysqlHandler(Logger::DEBUG)); + break; + } } + self::$is_initialized = true; } } diff --git a/lib/Froxlor/Http/HttpClient.php b/lib/Froxlor/Http/HttpClient.php index 6f5acb00..5b0e764a 100644 --- a/lib/Froxlor/Http/HttpClient.php +++ b/lib/Froxlor/Http/HttpClient.php @@ -11,7 +11,7 @@ class HttpClient * * @return array */ - public static function urlGet($url, $follow_location = true) + public static function urlGet($url, $follow_location = true, $timeout = 10) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); @@ -19,6 +19,7 @@ class HttpClient if ($follow_location) { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); } + curl_setopt($ch, CURLOPT_TIMEOUT, (int)$timeout); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); if ($output === false) { diff --git a/lib/Froxlor/MailLogParser.php b/lib/Froxlor/MailLogParser.php index 1463da2f..f8800e89 100644 --- a/lib/Froxlor/MailLogParser.php +++ b/lib/Froxlor/MailLogParser.php @@ -101,13 +101,13 @@ class MailLogParser $timestamp = $this->getLogTimestamp($line); if ($this->startTime < $timestamp) { - if (preg_match("/postfix\/qmgr.*(?::|\])\s([A-Z\d]+).*from=?, size=(\d+),/", $line, $matches)) { + if (preg_match("/postfix\/qmgr.*(?::|\])\s([A-Z\d]+).*from=?, size=(\d+),/", $line, $matches)) { // Postfix from $this->mails[$matches[1]] = array( "domainFrom" => strtolower($matches[2]), "size" => $matches[3] ); - } elseif (preg_match("/postfix\/(?:pipe|smtp).*(?::|\])\s([A-Z\d]+).*to=?,/", $line, $matches)) { + } elseif (preg_match("/postfix\/(?:pipe|smtp).*(?::|\])\s([A-Z\d]+).*to=?,/", $line, $matches)) { // Postfix to if (array_key_exists($matches[1], $this->mails)) { $this->mails[$matches[1]]["domainTo"] = strtolower($matches[2]); diff --git a/lib/Froxlor/Settings.php b/lib/Froxlor/Settings.php index 88edf132..17dd0c43 100644 --- a/lib/Froxlor/Settings.php +++ b/lib/Froxlor/Settings.php @@ -263,6 +263,8 @@ class Settings self::init(); // empty update array self::$updatedata = array(); + // re-read in all settings + return self::readSettings(); } public static function loadSettingsInto(&$settings_data) diff --git a/lib/Froxlor/Settings/Store.php b/lib/Froxlor/Settings/Store.php index 9e3627f6..3371b921 100644 --- a/lib/Froxlor/Settings/Store.php +++ b/lib/Froxlor/Settings/Store.php @@ -27,29 +27,58 @@ class Store $returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue); if ($returnvalue !== false && is_array($fielddata) && isset($fielddata['settinggroup']) && $fielddata['settinggroup'] == 'system' && isset($fielddata['varname']) && $fielddata['varname'] == 'defaultip') { + self::updateStdSubdomainDefaultIp($newfieldvalue, $defaultips_old); + } - $customerstddomains_result_stmt = Database::prepare(" - SELECT `standardsubdomain` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `standardsubdomain` <> '0' - "); - Database::pexecute($customerstddomains_result_stmt); + return $returnvalue; + } - $ids = array(); + public static function storeSettingDefaultSslIp($fieldname, $fielddata, $newfieldvalue) + { + $defaultips_old = Settings::Get('system.defaultsslip'); - while ($customerstddomains_row = $customerstddomains_result_stmt->fetch(\PDO::FETCH_ASSOC)) { - $ids[] = (int) $customerstddomains_row['standardsubdomain']; + $returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue); + + if ($returnvalue !== false && is_array($fielddata) && isset($fielddata['settinggroup']) && $fielddata['settinggroup'] == 'system' && isset($fielddata['varname']) && $fielddata['varname'] == 'defaultsslip') { + self::updateStdSubdomainDefaultIp($newfieldvalue, $defaultips_old); + } + + return $returnvalue; + } + + private static function updateStdSubdomainDefaultIp($newfieldvalue, $defaultips_old) + { + // update standard-subdomain of customer if exists + $customerstddomains_result_stmt = Database::prepare(" + SELECT `standardsubdomain` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `standardsubdomain` <> '0' + "); + Database::pexecute($customerstddomains_result_stmt); + + $ids = array(); + while ($customerstddomains_row = $customerstddomains_result_stmt->fetch(\PDO::FETCH_ASSOC)) { + $ids[] = (int) $customerstddomains_row['standardsubdomain']; + } + + if (count($ids) > 0) { + $defaultips_new = explode(',', $newfieldvalue); + + if (! empty($defaultips_old) && ! empty($newfieldvalue)) { + $in_value = $defaultips_old . ", " . $newfieldvalue; + } elseif (! empty($defaultips_old) && empty($newfieldvalue)) { + $in_value = $defaultips_old; + } else { + $in_value = $newfieldvalue; } - if (count($ids) > 0) { - $defaultips_new = explode(',', $newfieldvalue); - - // Delete the existing mappings linking to default IPs - $del_stmt = Database::prepare(" - DELETE FROM `" . TABLE_DOMAINTOIP . "` - WHERE `id_domain` IN (" . implode(', ', $ids) . ") - AND `id_ipandports` IN (" . $defaultips_old . ", " . $newfieldvalue . ") - "); - Database::pexecute($del_stmt); + // Delete the existing mappings linking to default IPs + $del_stmt = Database::prepare(" + DELETE FROM `" . TABLE_DOMAINTOIP . "` + WHERE `id_domain` IN (" . implode(', ', $ids) . ") + AND `id_ipandports` IN (" . $in_value . ") + "); + Database::pexecute($del_stmt); + if (count($defaultips_new) > 0) { // Insert the new mappings $ins_stmt = Database::prepare(" INSERT INTO `" . TABLE_DOMAINTOIP . "` @@ -66,68 +95,6 @@ class Store } } } - - return $returnvalue; - } - - public static function storeSettingDefaultSslIp($fieldname, $fielddata, $newfieldvalue) - { - $defaultips_old = Settings::Get('system.defaultsslip'); - - $returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue); - - if ($returnvalue !== false && is_array($fielddata) && isset($fielddata['settinggroup']) && $fielddata['settinggroup'] == 'system' && isset($fielddata['varname']) && $fielddata['varname'] == 'defaultsslip') { - - $customerstddomains_result_stmt = Database::prepare(" - SELECT `standardsubdomain` FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `standardsubdomain` <> '0' - "); - Database::pexecute($customerstddomains_result_stmt); - - $ids = array(); - - while ($customerstddomains_row = $customerstddomains_result_stmt->fetch(\PDO::FETCH_ASSOC)) { - $ids[] = (int) $customerstddomains_row['standardsubdomain']; - } - - if (count($ids) > 0) { - $defaultips_new = explode(',', $newfieldvalue); - - if (! empty($defaultips_old) && ! empty($newfieldvalue)) { - $in_value = $defaultips_old . ", " . $newfieldvalue; - } elseif (! empty($defaultips_old) && empty($newfieldvalue)) { - $in_value = $defaultips_old; - } else { - $in_value = $newfieldvalue; - } - - // Delete the existing mappings linking to default IPs - $del_stmt = Database::prepare(" - DELETE FROM `" . TABLE_DOMAINTOIP . "` - WHERE `id_domain` IN (" . implode(', ', $ids) . ") - AND `id_ipandports` IN (" . $in_value . ") - "); - Database::pexecute($del_stmt); - - if (count($defaultips_new) > 0) { - // Insert the new mappings - $ins_stmt = Database::prepare(" - INSERT INTO `" . TABLE_DOMAINTOIP . "` - SET `id_domain` = :domainid, `id_ipandports` = :ipandportid - "); - - foreach ($ids as $id) { - foreach ($defaultips_new as $defaultip_new) { - Database::pexecute($ins_stmt, array( - 'domainid' => $id, - 'ipandportid' => $defaultip_new - )); - } - } - } - } - } - - return $returnvalue; } /** @@ -143,25 +110,24 @@ class Store */ public static function storeSettingDefaultTheme($fieldname, $fielddata, $newfieldvalue) { - // first save the setting itself $returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue); if ($returnvalue !== false && is_array($fielddata) && isset($fielddata['settinggroup']) && $fielddata['settinggroup'] == 'panel' && isset($fielddata['varname']) && $fielddata['varname'] == 'default_theme') { - // now, if changing themes is disabled we recursivly set + // now, if changing themes is disabled we manually set // the new theme (customers and admin, depending on settings) if (Settings::Get('panel.allow_theme_change_customer') == '0') { $upd_stmt = Database::prepare(" - UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `theme` = :theme - "); + UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `theme` = :theme + "); Database::pexecute($upd_stmt, array( 'theme' => $newfieldvalue )); } if (Settings::Get('panel.allow_theme_change_admin') == '0') { $upd_stmt = Database::prepare(" - UPDATE `" . TABLE_PANEL_ADMINS . "` SET `theme` = :theme - "); + UPDATE `" . TABLE_PANEL_ADMINS . "` SET `theme` = :theme + "); Database::pexecute($upd_stmt, array( 'theme' => $newfieldvalue )); @@ -204,17 +170,13 @@ class Store public static function storeSettingFieldInsertBindTask($fieldname, $fielddata, $newfieldvalue) { - if (is_array($fielddata) && isset($fielddata['settinggroup']) && $fielddata['settinggroup'] != '' && isset($fielddata['varname']) && $fielddata['varname'] != '') { - if (Settings::Set($fielddata['settinggroup'] . '.' . $fielddata['varname'], $newfieldvalue) !== false) { - return array( - $fielddata['settinggroup'] . '.' . $fielddata['varname'] => $newfieldvalue - ); - } else { - return false; - } - } else { - return false; + // first save the setting itself + $returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue); + + if ($returnvalue !== false) { + \Froxlor\System\Cronjob::inserttask('4'); } + return false; } public static function storeSettingHostname($fieldname, $fielddata, $newfieldvalue) @@ -352,25 +314,9 @@ class Store $returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue); if ($returnvalue !== false && is_array($fielddata) && isset($fielddata['settinggroup']) && $fielddata['settinggroup'] == 'catchall' && isset($fielddata['varname']) && $fielddata['varname'] == 'catchall_enabled' && $newfieldvalue == '0') { - - $result_stmt = Database::query(" - SELECT `id`, `email`, `email_full`, `iscatchall` FROM `" . TABLE_MAIL_VIRTUAL . "` - WHERE `iscatchall` = '1' + Database::query(" + UPDATE `" . TABLE_MAIL_VIRTUAL . "` SET `iscatchall` = '0' WHERE `iscatchall` = '1' "); - - if (Database::num_rows() > 0) { - - $upd_stmt = Database::prepare(" - UPDATE `" . TABLE_MAIL_VIRTUAL . "` SET `email` = :email, `iscatchall` = '0' WHERE `id` = :id - "); - - while ($result_row = $result_stmt->fetch(\PDO::FETCH_ASSOC)) { - Database::pexecute($upd_stmt, array( - 'email' => $result_row['email_full'], - 'id' => $result_row['id'] - )); - } - } } return $returnvalue; diff --git a/lib/Froxlor/System/Cronjob.php b/lib/Froxlor/System/Cronjob.php index bf7debfa..a08dbaa0 100644 --- a/lib/Froxlor/System/Cronjob.php +++ b/lib/Froxlor/System/Cronjob.php @@ -178,6 +178,14 @@ class Cronjob 'type' => '11', 'data' => $data )); + } elseif ($type == '12' && $param1 != '') { + $data = array(); + $data['domain'] = $param1; + $data = json_encode($data); + Database::pexecute($ins_stmt, array( + 'type' => '12', + 'data' => $data + )); } elseif ($type == '20' && is_array($param1)) { $data = json_encode($param1); Database::pexecute($ins_stmt, array( @@ -277,6 +285,9 @@ class Cronjob } elseif ($row['type'] == '11') { // remove domain from pdns database if used $task_desc = sprintf($lng['tasks']['remove_pdns_domain'], $row['data']['domain']); + } elseif ($row['type'] == '12') { + // remove domains ssl files + $task_desc = sprintf($lng['tasks']['remove_ssl_domain'], $row['data']['domain']); } elseif ($row['type'] == '20') { // deleting user-files $loginname = ''; @@ -350,4 +361,14 @@ class Cronjob die($message); } + + public static function updateLastRunOfCron($cronname) + { + $upd_stmt = Database::prepare(" + UPDATE `" . TABLE_PANEL_CRONRUNS . "` SET `lastrun` = UNIX_TIMESTAMP() WHERE `cronfile` = :cron; + "); + Database::pexecute($upd_stmt, array( + 'cron' => $cronname + )); + } } diff --git a/lib/Froxlor/System/MysqlHandler.php b/lib/Froxlor/System/MysqlHandler.php index b0dc3647..1703d34a 100644 --- a/lib/Froxlor/System/MysqlHandler.php +++ b/lib/Froxlor/System/MysqlHandler.php @@ -57,7 +57,7 @@ class MysqlHandler extends AbstractProcessingHandler { $this->insert([ ':message' => $record['message'], - ':contextUser' => (isset($record['context']['loginname']) ? $record['context']['loginname'] : 'unknown'), + ':contextUser' => (isset($record['context']['user']) ? $record['context']['user'] : 'unknown'), ':contextAction' => (isset($record['context']['action']) ? $record['context']['action'] : '0'), ':level' => self::$froxlorLevels[$record['level']], ':datetime' => $record['datetime']->format('U') diff --git a/lib/Froxlor/UI/Paging.php b/lib/Froxlor/UI/Paging.php index 635f9ffd..6b7e5ee7 100644 --- a/lib/Froxlor/UI/Paging.php +++ b/lib/Froxlor/UI/Paging.php @@ -282,7 +282,7 @@ class Paging $field .= '`'; } - if ($field{0} != '`') { + if ($field[0] != '`') { $field = '`' . $field; } @@ -352,7 +352,7 @@ class Paging $field .= '`'; } - if ($field{0} != '`') { + if ($field[0] != '`') { $field = '`' . $field; } diff --git a/lib/Froxlor/Validate/Check.php b/lib/Froxlor/Validate/Check.php index 147afb5a..14f30fe3 100644 --- a/lib/Froxlor/Validate/Check.php +++ b/lib/Froxlor/Validate/Check.php @@ -192,7 +192,7 @@ class Check } $returnvalue = array(); - if (Validate::validateUsername($newfieldvalue, Settings::Get('panel.unix_names'), 14 - strlen($allnewfieldvalues['customer_mysqlprefix'])) === true) { + if (Validate::validateUsername($newfieldvalue, Settings::Get('panel.unix_names'), \Froxlor\Database\Database::getSqlUsernameLength() - strlen($allnewfieldvalues['customer_mysqlprefix'])) === true) { $returnvalue = array( self::FORMFIELDS_PLAUSIBILITY_CHECK_OK ); diff --git a/lib/Froxlor/Validate/Form/Data.php b/lib/Froxlor/Validate/Form/Data.php index a746ed17..713266b3 100644 --- a/lib/Froxlor/Validate/Form/Data.php +++ b/lib/Froxlor/Validate/Form/Data.php @@ -33,7 +33,7 @@ class Data if (isset($fielddata['string_type']) && $fielddata['string_type'] == 'mail') { $returnvalue = (filter_var($newfieldvalue, FILTER_VALIDATE_EMAIL) == $newfieldvalue); } elseif (isset($fielddata['string_type']) && $fielddata['string_type'] == 'url') { - $returnvalue = self::validateUrl($newfieldvalue); + $returnvalue = \Froxlor\Validate\Validate::validateUrl($newfieldvalue); } elseif (isset($fielddata['string_type']) && $fielddata['string_type'] == 'dir') { // check for empty value (it might be allowed) if (trim($newfieldvalue) == '') { @@ -128,62 +128,6 @@ class Data } } - /** - * Returns whether a URL is in a correct format or not - * - * @param string $url - * URL to be tested - * @return bool - * @author Christian Hoffmann - * @author Froxlor team (2010-) - * - */ - public static function validateUrl($url) - { - if (strtolower(substr($url, 0, 7)) != "http://" && strtolower(substr($url, 0, 8)) != "https://") { - $url = 'http://' . $url; - } - - // needs converting - try { - $idna_convert = new \Froxlor\Idna\IdnaWrapper(); - $url = $idna_convert->encode($url); - } catch (\Exception $e) { - return false; - } - - $pattern = '%^(?:(?:https?)://)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:/[^\s]*)?$%iuS'; - if (preg_match($pattern, $url)) { - return true; - } - - // not an fqdn - if (strtolower(substr($url, 0, 7)) == "http://" || strtolower(substr($url, 0, 8)) == "https://") { - if (strtolower(substr($url, 0, 7)) == "http://") { - $ip = strtolower(substr($url, 7)); - } - - if (strtolower(substr($url, 0, 8)) == "https://") { - $ip = strtolower(substr($url, 8)); - } - - $ip = substr($ip, 0, strpos($ip, '/')); - // possible : in IP (when a port is given), #1173 - // but only if there actually IS ONE - if (strpos($ip, ':') !== false) { - $ip = substr($ip, 0, strpos($ip, ':')); - } - - if (\Froxlor\Validate\Validate::validate_ip2($ip, true) !== false) { - return true; - } else { - return false; - } - } else { - return false; - } - } - public static function validateFormFieldBool($fieldname, $fielddata, $newfieldvalue) { if ($newfieldvalue === '1' || $newfieldvalue === 1 || $newfieldvalue === true || strtolower($newfieldvalue) === 'yes' || strtolower($newfieldvalue) === 'ja' || $newfieldvalue === '0' || $newfieldvalue === 0 || $newfieldvalue === false || strtolower($newfieldvalue) === 'no' || strtolower($newfieldvalue) === 'nein' || strtolower($newfieldvalue) === '') { @@ -252,7 +196,7 @@ class Data if (isset($fielddata['string_type']) && $fielddata['string_type'] == 'mail') { $returnvalue = (filter_var($newfieldvalue, FILTER_VALIDATE_EMAIL) == $newfieldvalue); } elseif (isset($fielddata['string_type']) && $fielddata['string_type'] == 'url') { - $returnvalue = \Froxlor\Validate\Form\Data::validateUrl($newfieldvalue); + $returnvalue = \Froxlor\Validate\Validate::validateUrl($newfieldvalue); } elseif (isset($fielddata['string_type']) && $fielddata['string_type'] == 'dir') { // add trailing slash to validate path if needed // refs #331 diff --git a/lib/Froxlor/Validate/Validate.php b/lib/Froxlor/Validate/Validate.php index b154439c..fa8e21af 100644 --- a/lib/Froxlor/Validate/Validate.php +++ b/lib/Froxlor/Validate/Validate.php @@ -23,8 +23,6 @@ class Validate */ public static function validate($str, $fieldname, $pattern = '', $lng = '', $emptydefault = array(), $throw_exception = false) { - global $log; - if (! is_array($emptydefault)) { $emptydefault_array = array( $emptydefault @@ -35,8 +33,8 @@ class Validate } // Check if the $str is one of the values which represent the default for an 'empty' value - if (is_array($emptydefault) && ! empty($emptydefault) && in_array($str, $emptydefault) && isset($emptydefault[0])) { - return $emptydefault[0]; + if (is_array($emptydefault) && ! empty($emptydefault) && in_array($str, $emptydefault)) { + return $str; } if ($pattern == '') { @@ -48,6 +46,7 @@ class Validate // everything else is removed from the string. $allowed = "/[^a-z0-9\\040\\.\\-\\_\\\\]/i"; $str = preg_replace($allowed, "", $str); + $log = \Froxlor\FroxlorLogger::getInstanceOf(); $log->logAction(\Froxlor\FroxlorLogger::USR_ACTION, LOG_WARNING, "cleaned bad formatted string (" . $str . ")"); } } @@ -61,7 +60,6 @@ class Validate } \Froxlor\UI\Response::standard_error($lng, $fieldname, $throw_exception); - exit(); } /** @@ -122,7 +120,6 @@ class Validate return false; } else { \Froxlor\UI\Response::standard_error($lng, $ip, $throw_exception); - exit(); } } @@ -141,10 +138,39 @@ class Validate return false; } else { \Froxlor\UI\Response::standard_error($lng, $ip, $throw_exception); - exit(); } } + /** + * Returns whether a URL is in a correct format or not + * + * @param string $url + * URL to be tested + * + * @return bool + */ + public static function validateUrl($url) + { + if (strtolower(substr($url, 0, 7)) != "http://" && strtolower(substr($url, 0, 8)) != "https://") { + $url = 'http://' . $url; + } + + // needs converting + try { + $idna_convert = new \Froxlor\Idna\IdnaWrapper(); + $url = $idna_convert->encode($url); + } catch (\Exception $e) { + return false; + } + + $pattern = '%^(?:(?:https?)://)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:/[^\s]*)?$%iuS'; + if (preg_match($pattern, $url)) { + return true; + } + + return false; + } + /** * Check if the submitted string is a valid domainname * @@ -180,7 +206,7 @@ class Validate */ public static function validateLocalHostname($hostname) { - $pattern = '/^([a-zA-Z0-9\-])+$/i'; + $pattern = '/^[a-z0-9][a-z0-9\-]{0,62}$/i'; if (preg_match($pattern, $hostname)) { return $hostname; } @@ -203,52 +229,59 @@ class Validate /** * Returns if an username is in correct format or not. * - * @param - * string The username to check - * @return bool Correct or not - * @author Michael Duergner - * + * @param string $username + * The username to check + * @param bool $unix_names + * optional, default true, checks whether it must be UNIX compatible + * @param int $mysql_max + * optional, number of max mysql username characters, default empty + * + * @return bool */ public static function validateUsername($username, $unix_names = 1, $mysql_max = '') { + if (empty($mysql_max) || ! is_numeric($mysql_max) || $mysql_max <= 0) { + $mysql_max = \Froxlor\Database\Database::getSqlUsernameLength() - 1; + } else { + $mysql_max --; + } if ($unix_names == 0) { if (strpos($username, '--') === false) { - return (preg_match('/^[a-z][a-z0-9\-_]{0,' . (int) ($mysql_max - 1) . '}[a-z0-9]{1}$/Di', $username) != false); - } else { - return false; + return (preg_match('/^[a-z][a-z0-9\-_]{0,' . $mysql_max . '}[a-z0-9]{1}$/Di', $username) != false); } - } else { - return (preg_match('/^[a-z][a-z0-9]{0,' . $mysql_max . '}$/Di', $username) != false); + return false; } + return (preg_match('/^[a-z][a-z0-9]{0,' . $mysql_max . '}$/Di', $username) != false); } + /** + * validate sql interval string + * + * @param string $interval + * + * @return boolean + */ public static function validateSqlInterval($interval = null) { - if (! $interval === null || $interval != '') { - if (strstr($interval, ' ') !== false) { - /* - * [0] = ([0-9]+) - * [1] = valid SQL-Interval expression - */ - $valid_expr = array( - 'SECOND', - 'MINUTE', - 'HOUR', - 'DAY', - 'WEEK', - 'MONTH', - 'YEAR' - ); + if (! empty($interval) && strstr($interval, ' ') !== false) { + /* + * [0] = ([0-9]+) + * [1] = valid SQL-Interval expression + */ + $valid_expr = array( + 'SECOND', + 'MINUTE', + 'HOUR', + 'DAY', + 'WEEK', + 'MONTH', + 'YEAR' + ); - $interval_parts = explode(' ', $interval); + $interval_parts = explode(' ', $interval); - if (is_array($interval_parts) && isset($interval_parts[0]) && isset($interval_parts[1])) { - if (preg_match('/([0-9]+)/i', $interval_parts[0])) { - if (in_array(strtoupper($interval_parts[1]), $valid_expr)) { - return true; - } - } - } + if (count($interval_parts) == 2 && preg_match('/[0-9]+/', $interval_parts[0]) && in_array(strtoupper($interval_parts[1]), $valid_expr)) { + return true; } } return false; diff --git a/lib/configfiles/bionic.xml b/lib/configfiles/bionic.xml index 314e1527..1c94f11b 100644 --- a/lib/configfiles/bionic.xml +++ b/lib/configfiles/bionic.xml @@ -1504,7 +1504,7 @@ user = password = dbname = hosts = -query = SELECT destination FROM mail_virtual WHERE email = '%s' AND trim(destination) <> '' +query = SELECT destination FROM mail_virtual AS v, panel_customers AS c WHERE c.customerid = v.customerid AND c.deactivated = 0 AND v.email = '%s' AND trim(v.destination) <> '' ]]> @@ -3746,7 +3746,7 @@ protocol sieve { # %m - number of messages (before deletion) # %s - mailbox size in bytes (before deletion) # %u - old/new UIDL hash. may help finding out if UIDLs changed unexpectedly -#pop3_logout_format = top=%t/%p, retr=%r/%b, del=%d/%m, size=%s +pop3_logout_format = in=%i out=%o top=%t/%p, retr=%r/%b, del=%d/%m, size=%s # Workarounds for various client bugs: # outlook-no-nuls: @@ -4539,21 +4539,7 @@ UPLOADGID= - - scripts/froxlor_master_cronjob.php -]]> - - + scripts/froxlor_master_cronjob.php --run-task 99]]> @@ -4568,8 +4554,8 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - + title="libnss-extrausers (required for FCGID/php-fpm/mpm-itk)"> + @@ -4601,9 +4587,6 @@ aliases: files ]]> - - - diff --git a/lib/configfiles/buster.xml b/lib/configfiles/buster.xml index f45784da..d95e6d02 100644 --- a/lib/configfiles/buster.xml +++ b/lib/configfiles/buster.xml @@ -1463,7 +1463,7 @@ user = password = dbname = hosts = -query = SELECT destination FROM mail_virtual WHERE email = '%s' AND trim(destination) <> '' +query = SELECT destination FROM mail_virtual AS v, panel_customers AS c WHERE c.customerid = v.customerid AND c.deactivated = 0 AND v.email = '%s' AND trim(v.destination) <> '' ]]> @@ -2593,7 +2593,7 @@ dict { # ); # Database driver: mysql, pgsql, sqlite -driver = mysql +driver = mysql # Database connection string. This is driver-specific setting. # @@ -2707,11 +2707,7 @@ user_query = SELECT CONCAT(homedir, maildir) AS home, CONCAT('maildir:', homedir password_query = SELECT username AS user, password_enc AS password, CONCAT(homedir, maildir) AS userdb_home, uid AS userdb_uid, gid AS userdb_gid, CONCAT('maildir:', homedir, maildir) AS userdb_mail, CONCAT('*:storage=', quota, 'M') as userdb_quota_rule FROM mail_users WHERE (username = '%u' OR email = '%u') AND ((imap = 1 AND '%Ls' = 'imap') OR (pop3 = 1 AND '%Ls' = 'pop3') OR ((postfix = 'Y' AND '%Ls' = 'smtp') OR (postfix = 'Y' AND '%Ls' = 'sieve'))) # Query to get a list of all usernames. -#iterate_query = SELECT username AS user FROM users - - -# This file is commonly accessed via passdb {} or userdb {} section in -# conf.d/auth-sql.conf.ext +#iterate_query = SELECT username AS user FROM mail_users ]]> @@ -3394,7 +3390,7 @@ service auth { unix_listener auth-client { mode = 0660 user = mail - # group = Debian-exim + #group = Debian-exim } # Auth process is run as this user. @@ -3417,6 +3413,17 @@ service dict { #group = } } + +service stats { + unix_listener stats-reader { + group = vmail + mode = 0666 + } + unix_listener stats-writer { + group = vmail + mode = 0666 + } +} ]]> @@ -3428,14 +3435,14 @@ service dict { ## # SSL/TLS support: yes, no, required. -ssl = no +ssl = yes # PEM encoded X.509 SSL/TLS certificate and private key. They're opened before # dropping root privileges, so keep the key file unreadable by anyone but # root. Included doc/mkcert.sh can be used to easily generate self-signed # certificate, just make sure to update the domains in dovecot-openssl.cnf -#ssl_cert = - - scripts/froxlor_master_cronjob.php -]]> - - + scripts/froxlor_master_cronjob.php --run-task 99]]> @@ -4763,8 +4756,8 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - + title="libnss-extrausers (required for FCGID/php-fpm/mpm-itk)"> + @@ -4796,9 +4789,6 @@ aliases: files ]]> - - - diff --git a/lib/configfiles/gentoo.xml b/lib/configfiles/gentoo.xml index 87424ed7..9f77e247 100644 --- a/lib/configfiles/gentoo.xml +++ b/lib/configfiles/gentoo.xml @@ -1474,7 +1474,7 @@ user = password = dbname = hosts = -query = SELECT destination FROM mail_virtual WHERE email = '%s' AND trim(destination) <> '' +query = SELECT destination FROM mail_virtual AS v, panel_customers AS c WHERE c.customerid = v.customerid AND c.deactivated = 0 AND v.email = '%s' AND trim(v.destination) <> '' ]]> @@ -3657,21 +3657,7 @@ account required pam_mysql.so user= passwd= - - scripts/froxlor_master_cronjob.php -]]> - - + scripts/froxlor_master_cronjob.php --run-task 99]]> diff --git a/lib/configfiles/jessie.xml b/lib/configfiles/jessie.xml index 2019e1c8..f46d836f 100644 --- a/lib/configfiles/jessie.xml +++ b/lib/configfiles/jessie.xml @@ -1504,7 +1504,7 @@ user = password = dbname = hosts = -query = SELECT destination FROM mail_virtual WHERE email = '%s' AND trim(destination) <> '' +query = SELECT destination FROM mail_virtual AS v, panel_customers AS c WHERE c.customerid = v.customerid AND c.deactivated = 0 AND v.email = '%s' AND trim(v.destination) <> '' ]]> @@ -3658,7 +3658,7 @@ protocol sieve { # %m - number of messages (before deletion) # %s - mailbox size in bytes (before deletion) # %u - old/new UIDL hash. may help finding out if UIDLs changed unexpectedly -#pop3_logout_format = top=%t/%p, retr=%r/%b, del=%d/%m, size=%s +pop3_logout_format = in=%i out=%o top=%t/%p, retr=%r/%b, del=%d/%m, size=%s # Workarounds for various client bugs: # outlook-no-nuls: @@ -4461,21 +4461,7 @@ UPLOADGID= - - scripts/froxlor_master_cronjob.php -]]> - - + scripts/froxlor_master_cronjob.php --run-task 99]]> @@ -4490,7 +4476,7 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + title="libnss-mysql (alternative for libnss-extrausers, required for FCGID/php-fpm/mpm-itk)"> - + title="libnss-extrausers (required for FCGID/php-fpm/mpm-itk)"> + @@ -4696,9 +4682,6 @@ aliases: files ]]> - - - diff --git a/lib/configfiles/rhel_centos.xml b/lib/configfiles/rhel_centos.xml index 68f9e544..3f6ab36a 100644 --- a/lib/configfiles/rhel_centos.xml +++ b/lib/configfiles/rhel_centos.xml @@ -95,7 +95,7 @@ user = password = dbname = hosts = -query = SELECT destination FROM mail_virtual WHERE email = '%s' AND trim(destination) <> '' +query = SELECT destination FROM mail_virtual AS v, panel_customers AS c WHERE c.customerid = v.customerid AND c.deactivated = 0 AND v.email = '%s' AND trim(v.destination) <> '' ]]> @@ -1529,7 +1529,7 @@ protocol sieve { # %m - number of messages (before deletion) # %s - mailbox size in bytes (before deletion) # %u - old/new UIDL hash. may help finding out if UIDLs changed unexpectedly -#pop3_logout_format = top=%t/%p, retr=%r/%b, del=%d/%m, size=%s +pop3_logout_format = in=%i out=%o top=%t/%p, retr=%r/%b, del=%d/%m, size=%s # Workarounds for various client bugs: # outlook-no-nuls: @@ -1826,7 +1826,7 @@ iterate_query = SELECT username AS user FROM mail_users - - - scripts/froxlor_master_cronjob.php -]]> - - + scripts/froxlor_master_cronjob.php --run-task 99]]> diff --git a/lib/configfiles/stretch.xml b/lib/configfiles/stretch.xml index e79883cc..6d717862 100644 --- a/lib/configfiles/stretch.xml +++ b/lib/configfiles/stretch.xml @@ -1493,7 +1493,7 @@ user = password = dbname = hosts = -query = SELECT destination FROM mail_virtual WHERE email = '%s' AND trim(destination) <> '' +query = SELECT destination FROM mail_virtual AS v, panel_customers AS c WHERE c.customerid = v.customerid AND c.deactivated = 0 AND v.email = '%s' AND trim(v.destination) <> '' ]]> @@ -3735,7 +3735,7 @@ protocol sieve { # %m - number of messages (before deletion) # %s - mailbox size in bytes (before deletion) # %u - old/new UIDL hash. may help finding out if UIDLs changed unexpectedly -#pop3_logout_format = top=%t/%p, retr=%r/%b, del=%d/%m, size=%s +pop3_logout_format = in=%i out=%o top=%t/%p, retr=%r/%b, del=%d/%m, size=%s # Workarounds for various client bugs: # outlook-no-nuls: @@ -4528,21 +4528,7 @@ UPLOADGID= - - scripts/froxlor_master_cronjob.php -]]> - - + scripts/froxlor_master_cronjob.php --run-task 99]]> @@ -4557,8 +4543,8 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - + title="libnss-extrausers (required for FCGID/php-fpm/mpm-itk)"> + @@ -4590,9 +4576,6 @@ aliases: files ]]> - - - diff --git a/lib/configfiles/trusty.xml b/lib/configfiles/trusty.xml index a37ea010..e9a1cf4d 100644 --- a/lib/configfiles/trusty.xml +++ b/lib/configfiles/trusty.xml @@ -502,7 +502,7 @@ user = password = dbname = hosts = -query = SELECT destination FROM mail_virtual WHERE email = '%s' AND trim(destination) <> '' +query = SELECT destination FROM mail_virtual AS v, panel_customers AS c WHERE c.customerid = v.customerid AND c.deactivated = 0 AND v.email = '%s' AND trim(v.destination) <> '' ]]> @@ -1546,21 +1546,7 @@ UPLOADGID= - - scripts/froxlor_master_cronjob.php -]]> - - + scripts/froxlor_master_cronjob.php --run-task 99]]> @@ -1575,7 +1561,7 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + title="libnss-mysql (alternative to libnss-extrausers, required for FCGID/php-fpm/mpm-itk)"> @@ -1671,8 +1657,8 @@ aliases: files - + title="libnss-extrausers (required for FCGID/php-fpm/mpm-itk)"> + @@ -1704,9 +1690,6 @@ aliases: files ]]> - - - diff --git a/lib/configfiles/xenial.xml b/lib/configfiles/xenial.xml index 50fc87c1..0345c524 100644 --- a/lib/configfiles/xenial.xml +++ b/lib/configfiles/xenial.xml @@ -1504,7 +1504,7 @@ user = password = dbname = hosts = -query = SELECT destination FROM mail_virtual WHERE email = '%s' AND trim(destination) <> '' +query = SELECT destination FROM mail_virtual AS v, panel_customers AS c WHERE c.customerid = v.customerid AND c.deactivated = 0 AND v.email = '%s' AND trim(v.destination) <> '' ]]> @@ -3746,7 +3746,7 @@ protocol sieve { # %m - number of messages (before deletion) # %s - mailbox size in bytes (before deletion) # %u - old/new UIDL hash. may help finding out if UIDLs changed unexpectedly -#pop3_logout_format = top=%t/%p, retr=%r/%b, del=%d/%m, size=%s +pop3_logout_format = in=%i out=%o top=%t/%p, retr=%r/%b, del=%d/%m, size=%s # Workarounds for various client bugs: # outlook-no-nuls: @@ -4539,21 +4539,7 @@ UPLOADGID= - - scripts/froxlor_master_cronjob.php -]]> - - + scripts/froxlor_master_cronjob.php --run-task 99]]> @@ -4568,8 +4554,8 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - + title="libnss-extrausers (required for FCGID/php-fpm/mpm-itk)"> + @@ -4601,9 +4587,6 @@ aliases: files ]]> - - - diff --git a/lib/formfields/admin/admin/formfield.admin_add.php b/lib/formfields/admin/admin/formfield.admin_add.php index d2ac4b67..24b41211 100644 --- a/lib/formfields/admin/admin/formfield.admin_add.php +++ b/lib/formfields/admin/admin/formfield.admin_add.php @@ -44,6 +44,21 @@ return array( 'label' => $lng['login']['language'], 'type' => 'select', 'select_var' => $language_options + ), + 'api_allowed' => array( + 'label' => $lng['usersettings']['api_allowed']['title'], + 'desc' => $lng['usersettings']['api_allowed']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + '1' + ), + 'visible' => (\Froxlor\Settings::Get('api.enabled') == '1' ? true : false) ) ) ), diff --git a/lib/formfields/admin/admin/formfield.admin_edit.php b/lib/formfields/admin/admin/formfield.admin_edit.php index b0b7f5a4..4827d4ae 100644 --- a/lib/formfields/admin/admin/formfield.admin_edit.php +++ b/lib/formfields/admin/admin/formfield.admin_edit.php @@ -59,6 +59,21 @@ return array( 'type' => 'select', 'select_var' => $language_options, 'visible' => ($result['adminid'] == $userinfo['userid'] ? false : true) + ), + 'api_allowed' => array( + 'label' => $lng['usersettings']['api_allowed']['title'], + 'desc' => $lng['usersettings']['api_allowed']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['api_allowed'] + ), + 'visible' => (\Froxlor\Settings::Get('api.enabled') == '1' ? true : false) ) ) ), diff --git a/lib/formfields/admin/customer/formfield.customer_add.php b/lib/formfields/admin/customer/formfield.customer_add.php index 2afb1b2b..ede3cc94 100644 --- a/lib/formfields/admin/customer/formfield.customer_add.php +++ b/lib/formfields/admin/customer/formfield.customer_add.php @@ -81,6 +81,21 @@ return array( 'label' => $lng['login']['language'], 'type' => 'select', 'select_var' => $language_options + ), + 'api_allowed' => array( + 'label' => $lng['usersettings']['api_allowed']['title'], + 'desc' => $lng['usersettings']['api_allowed']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + '1' + ), + 'visible' => (\Froxlor\Settings::Get('api.enabled') == '1' ? true : false) ) ) ), @@ -294,9 +309,9 @@ return array( 'values' => $phpconfigs, 'value' => ((int) \Froxlor\Settings::Get('system.mod_fcgid') == 1 ? array( \Froxlor\Settings::Get('system.mod_fcgid_defaultini') - ) : (int) \Froxlor\Settings::Get('phpfpm.enabled') == 1 ? array( + ) : ((int) \Froxlor\Settings::Get('phpfpm.enabled') == 1 ? array( \Froxlor\Settings::Get('phpfpm.defaultini') - ) : array()), + ) : array())), 'is_array' => 1 ), 'perlenabled' => array( diff --git a/lib/formfields/admin/customer/formfield.customer_edit.php b/lib/formfields/admin/customer/formfield.customer_edit.php index 9f5879da..47980f3c 100644 --- a/lib/formfields/admin/customer/formfield.customer_edit.php +++ b/lib/formfields/admin/customer/formfield.customer_edit.php @@ -74,6 +74,21 @@ return array( 'label' => $lng['login']['language'], 'type' => 'select', 'select_var' => $language_options + ), + 'api_allowed' => array( + 'label' => $lng['usersettings']['api_allowed']['title'], + 'desc' => $lng['usersettings']['api_allowed']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['api_allowed'] + ), + 'visible' => (\Froxlor\Settings::Get('api.enabled') == '1' ? true : false) ) ) ), diff --git a/lib/formfields/admin/domains/formfield.domains_add.php b/lib/formfields/admin/domains/formfield.domains_add.php index 48b7b243..05b4e8f8 100644 --- a/lib/formfields/admin/domains/formfield.domains_add.php +++ b/lib/formfields/admin/domains/formfield.domains_add.php @@ -180,12 +180,18 @@ return array( 'image' => 'icons/domain_add.png', 'visible' => \Froxlor\Settings::Get('system.use_ssl') == '1' ? true : false, 'fields' => array( + 'no_ssl_available_info' => array( + 'visible' => ($ssl_ipsandports == '' ? true : false), + 'label' => 'SSL', + 'type' => 'label', + 'value' => $lng['panel']['nosslipsavailable'] + ), 'ssl_ipandport' => array( 'label' => $lng['domains']['ipandport_ssl_multi']['title'], 'desc' => $lng['domains']['ipandport_ssl_multi']['description'], 'type' => 'checkbox', 'values' => $ssl_ipsandports, - 'value' => '', + 'value' => explode(',', \Froxlor\Settings::Get('system.defaultsslip')), 'is_array' => 1 ), 'ssl_redirect' => array( @@ -227,11 +233,81 @@ return array( ), 'value' => array() ), - 'no_ssl_available_info' => array( - 'visible' => ($ssl_ipsandports == '' ? true : false), - 'label' => 'SSL', - 'type' => 'label', - 'value' => $lng['panel']['nosslipsavailable'] + 'override_tls' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' ? true : false), + 'label' => $lng['admin']['domain_override_tls'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array() + ), + 'ssl_protocols' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' ? true : false), + 'label' => $lng['serversettings']['ssl']['ssl_protocols']['title'], + 'desc' => $lng['serversettings']['ssl']['ssl_protocols']['description'], + 'type' => 'checkbox', + 'value' => array( + 'TLSv1', + 'TLSv1.2' + ), + 'values' => array( + array( + 'value' => 'TLSv1', + 'label' => 'TLSv1
' + ), + array( + 'value' => 'TLSv1.1', + 'label' => 'TLSv1.1
' + ), + array( + 'value' => 'TLSv1.2', + 'label' => 'TLSv1.2
' + ), + array( + 'value' => 'TLSv1.3', + 'label' => 'TLSv1.3
' + ) + ), + 'is_array' => 1 + ), + 'ssl_cipher_list' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' ? true : false), + 'label' => $lng['serversettings']['ssl']['ssl_cipher_list']['title'], + 'desc' => $lng['serversettings']['ssl']['ssl_cipher_list']['description'], + 'type' => 'text', + 'value' => \Froxlor\Settings::Get('system.ssl_cipher_list') + ), + 'tlsv13_cipher_list' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' && \Froxlor\Settings::Get('system.webserver') == "apache2" && \Froxlor\Settings::Get('system.apache24') == 1 ? true : false), + 'label' => $lng['serversettings']['ssl']['tlsv13_cipher_list']['title'], + 'desc' => $lng['serversettings']['ssl']['tlsv13_cipher_list']['description'], + 'type' => 'text', + 'value' => \Froxlor\Settings::Get('system.tlsv13_cipher_list') + ), + 'ssl_specialsettings' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' ? true : false), + 'style' => 'align-top', + 'label' => $lng['admin']['ownsslvhostsettings'], + 'desc' => $lng['serversettings']['default_vhostconf']['description'], + 'type' => 'textarea', + 'cols' => 60, + 'rows' => 12 + ), + 'include_specialsettings' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' ? true : false), + 'label' => $lng['admin']['include_ownvhostsettings'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array() ), 'hsts_maxage' => array( 'visible' => ($ssl_ipsandports != '' ? true : false), diff --git a/lib/formfields/admin/domains/formfield.domains_edit.php b/lib/formfields/admin/domains/formfield.domains_edit.php index 4c756ec1..22d9eea2 100644 --- a/lib/formfields/admin/domains/formfield.domains_edit.php +++ b/lib/formfields/admin/domains/formfield.domains_edit.php @@ -212,6 +212,12 @@ return array( 'image' => 'icons/domain_edit.png', 'visible' => \Froxlor\Settings::Get('system.use_ssl') == '1' ? true : false, 'fields' => array( + 'no_ssl_available_info' => array( + 'visible' => ($ssl_ipsandports == '' ? true : false), + 'label' => 'SSL', + 'type' => 'label', + 'value' => $lng['panel']['nosslipsavailable'] + ), 'ssl_ipandport' => array( 'label' => $lng['domains']['ipandport_ssl_multi']['title'], 'desc' => $lng['domains']['ipandport_ssl_multi']['description'], @@ -265,11 +271,82 @@ return array( $result['http2'] ) ), - 'no_ssl_available_info' => array( - 'visible' => ($ssl_ipsandports == '' ? true : false), - 'label' => 'SSL', - 'type' => 'label', - 'value' => $lng['panel']['nosslipsavailable'] + 'override_tls' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' ? true : false), + 'label' => $lng['admin']['domain_override_tls'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['override_tls'] + ) + ), + 'ssl_protocols' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' ? true : false), + 'label' => $lng['serversettings']['ssl']['ssl_protocols']['title'], + 'desc' => $lng['serversettings']['ssl']['ssl_protocols']['description'], + 'type' => 'checkbox', + 'value' => !empty($result['ssl_protocols']) ? explode(",", $result['ssl_protocols']) : explode(",", \Froxlor\Settings::Get('system.ssl_protocols')), + 'values' => array( + array( + 'value' => 'TLSv1', + 'label' => 'TLSv1
' + ), + array( + 'value' => 'TLSv1.1', + 'label' => 'TLSv1.1
' + ), + array( + 'value' => 'TLSv1.2', + 'label' => 'TLSv1.2
' + ), + array( + 'value' => 'TLSv1.3', + 'label' => 'TLSv1.3
' + ) + ), + 'is_array' => 1 + ), + 'ssl_cipher_list' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' ? true : false), + 'label' => $lng['serversettings']['ssl']['ssl_cipher_list']['title'], + 'desc' => $lng['serversettings']['ssl']['ssl_cipher_list']['description'], + 'type' => 'text', + 'value' => !empty($result['ssl_cipher_list']) ? $result['ssl_cipher_list'] : \Froxlor\Settings::Get('system.ssl_cipher_list') + ), + 'tlsv13_cipher_list' => array( + 'visible' => (($ssl_ipsandports != '' ? true : false) && $userinfo['change_serversettings'] == '1' && \Froxlor\Settings::Get('system.webserver') == "apache2" && \Froxlor\Settings::Get('system.apache24') == 1 ? true : false), + 'label' => $lng['serversettings']['ssl']['tlsv13_cipher_list']['title'], + 'desc' => $lng['serversettings']['ssl']['tlsv13_cipher_list']['description'], + 'type' => 'text', + 'value' => !empty($result['tlsv13_cipher_list']) ? $result['tlsv13_cipher_list'] : \Froxlor\Settings::Get('system.tlsv13_cipher_list') + ), + 'ssl_specialsettings' => array( + 'visible' => ($userinfo['change_serversettings'] == '1' ? true : false), + 'style' => 'align-top', + 'label' => $lng['admin']['ownsslvhostsettings'], + 'desc' => $lng['serversettings']['default_vhostconf']['description'], + 'type' => 'textarea', + 'cols' => 60, + 'rows' => 12, + 'value' => $result['ssl_specialsettings'] + ), + 'include_specialsettings' => array( + 'label' => $lng['admin']['include_ownvhostsettings'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['include_specialsettings'] + ) ), 'hsts_maxage' => array( 'visible' => ($ssl_ipsandports != '' ? true : false), diff --git a/lib/formfields/admin/ipsandports/formfield.ipsandports_add.php b/lib/formfields/admin/ipsandports/formfield.ipsandports_add.php index 9a1348f0..3d10f7c3 100644 --- a/lib/formfields/admin/ipsandports/formfield.ipsandports_add.php +++ b/lib/formfields/admin/ipsandports/formfield.ipsandports_add.php @@ -119,6 +119,26 @@ return array( 'type' => 'textarea', 'cols' => 60, 'rows' => 12 + ), + 'ssl_default_vhostconf_domain' => array( + 'visible' => (\Froxlor\Settings::Get('system.use_ssl') == 1 ? true : false), + 'style' => 'align-top', + 'label' => $lng['admin']['ipsandports']['ssl_default_vhostconf_domain'], + 'desc' => $lng['serversettings']['default_vhostconf_domain']['description'], + 'type' => 'textarea', + 'cols' => 60, + 'rows' => 12 + ), + 'include_default_vhostconf_domain' => array( + 'label' => $lng['admin']['include_ownvhostsettings'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array() ) ) ), @@ -154,6 +174,25 @@ return array( 'label' => $lng['admin']['ipsandports']['ssl_cert_chainfile']['title'], 'desc' => $lng['admin']['ipsandports']['ssl_cert_chainfile']['description'], 'type' => 'text' + ), + 'ssl_specialsettings' => array( + 'style' => 'align-top', + 'label' => $lng['admin']['ownsslvhostsettings'], + 'desc' => $lng['serversettings']['default_vhostconf']['description'], + 'type' => 'textarea', + 'cols' => 60, + 'rows' => 12 + ), + 'include_specialsettings' => array( + 'label' => $lng['admin']['include_ownvhostsettings'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array() ) ) ) diff --git a/lib/formfields/admin/ipsandports/formfield.ipsandports_edit.php b/lib/formfields/admin/ipsandports/formfield.ipsandports_edit.php index efa5161b..b9148678 100644 --- a/lib/formfields/admin/ipsandports/formfield.ipsandports_edit.php +++ b/lib/formfields/admin/ipsandports/formfield.ipsandports_edit.php @@ -124,6 +124,29 @@ return array( 'cols' => 60, 'rows' => 12, 'value' => $result['default_vhostconf_domain'] + ), + 'ssl_default_vhostconf_domain' => array( + 'visible' => (\Froxlor\Settings::Get('system.use_ssl') == 1 ? true : false), + 'style' => 'align-top', + 'label' => $lng['admin']['ipsandports']['ssl_default_vhostconf_domain'], + 'desc' => $lng['serversettings']['default_vhostconf_domain']['description'], + 'type' => 'textarea', + 'cols' => 60, + 'rows' => 12, + 'value' => $result['ssl_default_vhostconf_domain'] + ), + 'include_default_vhostconf_domain' => array( + 'label' => $lng['admin']['include_ownvhostsettings'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['include_default_vhostconf_domain'] + ) ) ) ), @@ -165,6 +188,28 @@ return array( 'desc' => $lng['admin']['ipsandports']['ssl_cert_chainfile']['description'], 'type' => 'text', 'value' => $result['ssl_cert_chainfile'] + ), + 'ssl_specialsettings' => array( + 'style' => 'align-top', + 'label' => $lng['admin']['ownsslvhostsettings'], + 'desc' => $lng['serversettings']['default_vhostconf']['description'], + 'type' => 'textarea', + 'cols' => 60, + 'rows' => 12, + 'value' => $result['ssl_specialsettings'] + ), + 'include_specialsettings' => array( + 'label' => $lng['admin']['include_ownvhostsettings'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['include_specialsettings'] + ) ) ) ) diff --git a/lib/formfields/customer/domains/formfield.domain_ssleditor.php b/lib/formfields/customer/domains/formfield.domain_ssleditor.php index e6a14faa..3518ef39 100644 --- a/lib/formfields/customer/domains/formfield.domain_ssleditor.php +++ b/lib/formfields/customer/domains/formfield.domain_ssleditor.php @@ -23,6 +23,12 @@ return array( 'title' => 'SSL certificates', 'image' => 'icons/ssl.png', 'fields' => array( + 'domainname' => array( + 'label' => $lng['domains']['domainname'], + 'type' => 'hidden', + 'value' => $result_domain['domain'], + 'display' => $result_domain['domain'] + ), 'ssl_cert_file' => array( 'style' => 'align-top', 'label' => $lng['admin']['ipsandports']['ssl_cert_file_content'], diff --git a/lib/formfields/customer/domains/formfield.domains_add.php b/lib/formfields/customer/domains/formfield.domains_add.php index 00d9fca6..1e6f47eb 100644 --- a/lib/formfields/customer/domains/formfield.domains_add.php +++ b/lib/formfields/customer/domains/formfield.domains_add.php @@ -108,6 +108,19 @@ return array( ), 'value' => array() ), + 'http2' => array( + 'visible' => ($ssl_ipsandports != '' ? true : false) && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' && \Froxlor\Settings::Get('system.http2_support') == '1', + 'label' => $lng['admin']['domain_http2']['title'], + 'desc' => $lng['admin']['domain_http2']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array() + ), 'hsts_maxage' => array( 'label' => $lng['admin']['domain_hsts_maxage']['title'], 'desc' => $lng['admin']['domain_hsts_maxage']['description'], diff --git a/lib/formfields/customer/domains/formfield.domains_edit.php b/lib/formfields/customer/domains/formfield.domains_edit.php index 56a28543..0fd54134 100644 --- a/lib/formfields/customer/domains/formfield.domains_edit.php +++ b/lib/formfields/customer/domains/formfield.domains_edit.php @@ -128,6 +128,21 @@ return array( $result['letsencrypt'] ) ), + 'http2' => array( + 'visible' => ($ssl_ipsandports != '' ? true : false) && \Froxlor\Settings::Get('system.webserver') != 'lighttpd' && \Froxlor\Settings::Get('system.http2_support') == '1', + 'label' => $lng['admin']['domain_http2']['title'], + 'desc' => $lng['admin']['domain_http2']['description'], + 'type' => 'checkbox', + 'values' => array( + array( + 'label' => $lng['panel']['yes'], + 'value' => '1' + ) + ), + 'value' => array( + $result['http2'] + ) + ), 'hsts_maxage' => array( 'label' => $lng['admin']['domain_hsts_maxage']['title'], 'desc' => $lng['admin']['domain_hsts_maxage']['description'], diff --git a/lib/init.php b/lib/init.php index 2e57aa1c..acc2375c 100644 --- a/lib/init.php +++ b/lib/init.php @@ -16,6 +16,19 @@ * @package System * */ + +// define default theme for configurehint, etc. +$_deftheme = 'Sparkle'; + +if (! file_exists(dirname(__DIR__) . '/vendor/autoload.php')) { + // get hint-template + $vendor_hint = file_get_contents(dirname(__DIR__) . '/templates/' . $_deftheme . '/misc/vendormissinghint.tpl'); + // replace values + $vendor_hint = str_replace("", dirname(__DIR__), $vendor_hint); + $vendor_hint = str_replace("", date('Y', time()), $vendor_hint); + die($vendor_hint); +} + require dirname(__DIR__) . '/vendor/autoload.php'; use Froxlor\Database\Database; @@ -68,9 +81,6 @@ unset($key); $filename = htmlentities(basename($_SERVER['PHP_SELF'])); -// define default theme for configurehint, etc. -$_deftheme = 'Sparkle'; - // check whether the userdata file exists if (! file_exists(\Froxlor\Froxlor::getInstallDir() . '/lib/userdata.inc.php')) { $config_hint = file_get_contents(\Froxlor\Froxlor::getInstallDir() . '/templates/' . $_deftheme . '/misc/configurehint.tpl'); @@ -88,7 +98,7 @@ if (! is_readable(\Froxlor\Froxlor::getInstallDir() . '/lib/userdata.inc.php')) // replace values $owner_hint = str_replace("", $posixusername['name'], $owner_hint); $owner_hint = str_replace("", $posixgroup['name'], $owner_hint); - $owner_hint = str_replace("<\Froxlor\Froxlor::getInstallDir()>", \Froxlor\Froxlor::getInstallDir(), $owner_hint); + $owner_hint = str_replace("", \Froxlor\Froxlor::getInstallDir(), $owner_hint); $owner_hint = str_replace("", date('Y', time()), $owner_hint); // show die($owner_hint); @@ -210,7 +220,7 @@ if (isset($s) && $s != "" && $nosession != 1) { $userinfo_stmt = Database::prepare($query); $userinfo = Database::pexecute_first($userinfo_stmt, $userinfo_data); - if ((($userinfo['adminsession'] == '1' && AREA == 'admin' && isset($userinfo['adminid'])) || ($userinfo['adminsession'] == '0' && (AREA == 'customer' || AREA == 'login') && isset($userinfo['customerid']))) && (! isset($userinfo['deactivated']) || $userinfo['deactivated'] != '1')) { + if ($userinfo && (($userinfo['adminsession'] == '1' && AREA == 'admin' && isset($userinfo['adminid'])) || ($userinfo['adminsession'] == '0' && (AREA == 'customer' || AREA == 'login') && isset($userinfo['customerid']))) && (! isset($userinfo['deactivated']) || $userinfo['deactivated'] != '1')) { $upd_stmt = Database::prepare(" UPDATE `" . TABLE_PANEL_SESSIONS . "` SET `lastactivity` = :lastactive diff --git a/lib/navigation/00.froxlor.main.php b/lib/navigation/00.froxlor.main.php index bbc6896a..241d048f 100644 --- a/lib/navigation/00.froxlor.main.php +++ b/lib/navigation/00.froxlor.main.php @@ -44,7 +44,7 @@ return array( 'show_element' => (\Froxlor\Settings::Get('api.enabled') == true) ), array( - 'url' => 'customer_index.php?page=apihelp', + 'url' => 'https://api.froxlor.org/doc/?v='.\Froxlor\Froxlor::getVersion(), 'label' => $lng['menue']['main']['apihelp'], 'show_element' => (\Froxlor\Settings::Get('api.enabled') == true) ), @@ -195,7 +195,7 @@ return array( 'show_element' => (\Froxlor\Settings::Get('api.enabled') == true) ), array( - 'url' => 'admin_index.php?page=apihelp', + 'url' => 'https://api.froxlor.org/doc/?v='.\Froxlor\Froxlor::getVersion(), 'label' => $lng['menue']['main']['apihelp'], 'show_element' => (\Froxlor\Settings::Get('api.enabled') == true) ), diff --git a/lng/english.lng.php b/lng/english.lng.php index 964ec0b3..c61cdd79 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -502,7 +502,7 @@ $lng['panel']['pathDescriptionSubdomain'] = $lng['panel']['pathDescription'] . $ // ADDED IN 1.2.16-svn6 -$lng['admin']['templates']['TRAFFIC'] = 'Replaced with the traffic in mB, which was assigned to the customer.'; +$lng['admin']['templates']['TRAFFIC'] = 'Replaced with the traffic in MB, which was assigned to the customer.'; $lng['admin']['templates']['TRAFFICUSED'] = 'Replaced with the traffic in MB, which was exhausted by the customer.'; // ADDED IN 1.2.16-svn7 @@ -839,7 +839,8 @@ $lng['error']['nopermissionsorinvalidid'] = 'You don\'t have enough permissions $lng['panel']['view'] = 'view'; $lng['question']['phpsetting_reallydelete'] = 'Do you really want to delete these settings? All domains which use these settings currently will be changed to the default config.'; $lng['question']['fpmsetting_reallydelete'] = 'Do you really want to delete these php-fpm settings? All php configurations which use these settings currently will be changed to the default config.'; -$lng['admin']['phpsettings']['addnew'] = 'Create new settings'; +$lng['admin']['phpsettings']['addnew'] = 'Create new PHP configuration'; +$lng['admin']['fpmsettings']['addnew'] = 'Create new PHP version'; $lng['error']['phpsettingidwrong'] = 'A PHP Configuration with this id doesn\'t exist'; $lng['error']['descriptioninvalid'] = 'The description is too short, too long or contains illegal characters.'; $lng['error']['info'] = 'Info'; @@ -1626,7 +1627,7 @@ $lng['domains']['serveraliasoption_www'] = 'WWW (www.domain.tld)'; $lng['domains']['serveraliasoption_none'] = 'No alias'; $lng['error']['givendirnotallowed'] = 'The given directory in field %s is not allowed.'; $lng['serversettings']['ssl']['ssl_cipher_list']['title'] = 'Configure the allowed SSL ciphers'; -$lng['serversettings']['ssl']['ssl_cipher_list']['description'] = 'This is a list of ciphers that you want (or don\'t want) to use when talking SSL. For a list of ciphers and how to include/exclude them, see sections "CIPHER LIST FORMAT" and "CIPHER STRINGS" on the man-page for ciphers.

Default value is:
ECDH+AESGCM:ECDH+AES256:!aNULL:!MD5:!DSS:!DH:!AES128
'; +$lng['serversettings']['ssl']['ssl_cipher_list']['description'] = 'This is a list of ciphers that you want (or don\'t want) to use when talking SSL. For a list of ciphers and how to include/exclude them, see sections "CIPHER LIST FORMAT" and "CIPHER STRINGS" on the man-page for ciphers.

Default value is:
ECDH+AESGCM:ECDH+AES256:!aNULL:!MD5:!DSS:!DH:!AES128
'; // Added in Froxlor 0.9.31 $lng['panel']['dashboard'] = 'Dashboard'; @@ -1743,12 +1744,12 @@ $lng['admin']['configfiles']['commands'] = 'Commands: T $lng['admin']['configfiles']['files'] = 'Config files: The commands before the textfields should open an editor with the target file. Just copy and paste the contents into the editor and save the file.
Please note: The MySQL-password has not been replaced for security reasons. Please replace "FROXLOR_MYSQL_PASSWORD" on your own or use the javascript form below to replace it on-site. If you forgot your MySQL-password you\'ll find it in "lib/userdata.inc.php"'; $lng['serversettings']['apache_itksupport']['title'] = 'Use modifications for Apache ITK-MPM'; $lng['serversettings']['apache_itksupport']['description'] = 'ATTENTION: use only if you actually have apache itk-mpm enabled
otherwise your webserver will not be able to start'; -$lng['integrity_check']['DatabaseCharset'] = 'Character set of database (should be UTF-8)'; -$lng['integrity_check']['DomainIpTable'] = 'IP <‐> domain references'; -$lng['integrity_check']['SubdomainSslRedirect'] = 'False SSL-redirect flag for non-ssl domains'; -$lng['integrity_check']['FroxlorLocalGroupMemberForFcgidPhpFpm'] = 'froxlor-user in the customer groups (for FCGID/php-fpm)'; -$lng['integrity_check']['WebserverGroupMemberForFcgidPhpFpm'] = 'Webserver-user in the customer groups (for FCGID/php-fpm)'; -$lng['integrity_check']['SubdomainLetsencrypt'] = 'Main domains with no SSL-Port assigned don\'t have any subdomains with active SSL redirect'; +$lng['integrity_check']['databaseCharset'] = 'Character set of database (should be UTF-8)'; +$lng['integrity_check']['domainIpTable'] = 'IP <‐> domain references'; +$lng['integrity_check']['subdomainSslRedirect'] = 'False SSL-redirect flag for non-ssl domains'; +$lng['integrity_check']['froxlorLocalGroupMemberForFcgidPhpFpm'] = 'froxlor-user in the customer groups (for FCGID/php-fpm)'; +$lng['integrity_check']['webserverGroupMemberForFcgidPhpFpm'] = 'Webserver-user in the customer groups (for FCGID/php-fpm)'; +$lng['integrity_check']['subdomainLetsencrypt'] = 'Main domains with no SSL-Port assigned don\'t have any subdomains with active SSL redirect'; $lng['admin']['mod_fcgid_umask']['title'] = 'Umask (default: 022)'; // Added for apcuinfo @@ -1829,7 +1830,7 @@ $lng['admin']['letsencrypt']['description'] = 'Get a free certificate from . The certificate will be created and renewed automatically.
ATTENTION: This feature is still in beta.'; $lng['error']['sslredirectonlypossiblewithsslipport'] = 'Using Let\'s Encrypt is only possible when the domain has at least one ssl-enabled IP/port combination assigned.'; -$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt cannot handle wildcard-domains using ACME v1. Please set the ServerAlias to WWW or disable it completely'; +$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt cannot handle wildcard-domains using ACME in froxlor (requires dns-challenge), sorry. Please set the ServerAlias to WWW or disable it completely'; $lng['panel']['letsencrypt'] = 'Using Let\'s encrypt'; $lng['crondesc']['cron_letsencrypt'] = 'updating Let\'s Encrypt certificates'; $lng['serversettings']['letsencryptca']['title'] = "Let's Encrypt environment"; @@ -1848,6 +1849,12 @@ $lng['serversettings']['leenabled']['title'] = "Enable Let's Encrypt"; $lng['serversettings']['leenabled']['description'] = "If activated, customers are able to let froxlor automatically generate and renew Let's Encrypt ssl-certificates for domains with a ssl IP/port.

Please remember that you need to go through the webserver-configuration when enabled because this feature needs a special configuration."; $lng['domains']['ssl_redirect_temporarilydisabled'] = "
The SSL redirect is temporarily deactivated while a new Let's Encrypt certificate is generated. It will be activated again after the certificate was generated."; +// Added for CAA record support +$lng['serversettings']['caa_entry']['title'] = 'Generate CAA DNS records'; +$lng['serversettings']['caa_entry']['description'] = 'Automatically generates CAA records for SSL-enabled domains that are using Let\'s Encrypt'; +$lng['serversettings']['caa_entry_custom']['title'] = 'Additional CAA DNS records'; +$lng['serversettings']['caa_entry_custom']['description'] = 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities
whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record.

The content of this field will be included into the DNS zone directly (each line results in a CAA record).
If Let\'s Encrypt is enabled for this domain, this entry will always be added automatically and does not need to be added manually:
0 issue "letsencrypt.org" (If domain is a wildcard domain, issuewild will be used instead).
To enable Incident Reporting, you can add an iodef record. An example for sending such report to me@example.com would be:
0 iodef "mailto:me@example.com"

Attention: The code won\'t be checked for any errors. If it contains errors, your CAA records might not work!'; + // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; $lng['error']['customized_version'] = 'It looks like your Froxlor installation has been modified, no support sorry.'; @@ -1860,6 +1867,7 @@ $lng['error']['autoupdate_6'] = 'Whoops, there was no (valid) version given to d $lng['error']['autoupdate_7'] = 'The downloaded archive could not be found :('; $lng['error']['autoupdate_8'] = 'The archive could not be extracted :('; $lng['error']['autoupdate_9'] = 'The downloaded file did not pass the integrity check. Please try to update again.'; +$lng['error']['autoupdate_10'] = 'Minimum supported version of PHP is 7.0'; $lng['admin']['server_php'] = 'PHP'; $lng['domains']['termination_date'] = 'Date of termination'; @@ -1886,6 +1894,7 @@ $lng['tasks']['backup_customerfiles'] = 'Backup job for customer %loginname%'; $lng['error']['dns_domain_nodns'] = 'DNS is not enabled for this domain'; $lng['error']['dns_content_empty'] = 'No content given'; +$lng['error']['dns_content_invalid'] = 'DNS content invalid'; $lng['error']['dns_arec_noipv4'] = 'No valid IP address for A-record given'; $lng['error']['dns_aaaarec_noipv6'] = 'No valid IP address for AAAA-record given'; $lng['error']['dns_mx_prioempty'] = 'Invalid MX priority given'; @@ -1978,8 +1987,7 @@ $lng['admin']['phpsettings']['activephpconfigs'] = 'In use for php-config(s)'; $lng['admin']['phpsettingsforsubdomains'] = 'Apply php-config to all subdomains:'; $lng['serversettings']['phpsettingsforsubdomains']['description'] = 'If yes the chosen php-config will be updated to all subdomains'; $lng['serversettings']['leapiversion']['title'] = "Choose Let's Encrypt ACME implementation"; -$lng['serversettings']['leapiversion']['description'] = "Choose between ACME v1 and ACME v2 implementation for Let's Encrypt."; -$lng['error']['nowildcardwithletsencryptv2'] = 'Let\'s Encrypt can only validate wildcard-domains by DNS with ACME v2, sorry. Please set the ServerAlias to WWW or disable it completely'; +$lng['serversettings']['leapiversion']['description'] = "Currently only ACME v2 implementation for Let's Encrypt is supported."; $lng['admin']['phpsettings']['pass_authorizationheader'] = 'Add "-pass-header Authorization" / "CGIPassAuth On" to vhosts'; $lng['serversettings']['ssl']['ssl_protocols']['title'] = 'Configure the TLS protocol version'; $lng['serversettings']['ssl']['ssl_protocols']['description'] = 'This is a list of ssl protocols that you want (or don\'t want) to use when using SSL. Notice: Some older browsers may not support the newest protcol versions.

Default value is:
TLSv1, TLSv1.2
'; @@ -2051,6 +2059,7 @@ $lng['panel']['system_is_configured'] = 'System is already set as configured'; $lng['panel']['settings_before_configuration'] = 'Please be sure you adjusted the settings prior to configuring the services here'; $lng['panel']['alternative_cmdline_config'] = 'Alternatively, just run the following command as root-user in your shell to configure the services automatically'; $lng['tasks']['remove_pdns_domain'] = 'Delete domain %s from PowerDNS database'; +$lng['tasks']['remove_ssl_domain'] = 'Delete ssl files of domain %s'; $lng['admin']['novhostcontainer'] = '

None of the IPs and ports has the "' . $lng['admin']['ipsandports']['create_vhostcontainer'] . '" option enabled, many settings here will not be available'; $lng['serversettings']['errorlog_level']['title'] = 'Error log-level'; $lng['serversettings']['errorlog_level']['description'] = 'Specify the error log level. Default is "warn" for apache-users and "error" for nginx-users.'; @@ -2058,3 +2067,15 @@ $lng['serversettings']['letsencryptecc']['title'] = "Issue ECC / ECDSA certifica $lng['serversettings']['letsencryptecc']['description'] = "If set to a valid key-size the certificate issued will use ECC / ECDSA"; $lng['serversettings']['froxloraliases']['title'] = "Domain aliases for froxlor vhost"; $lng['serversettings']['froxloraliases']['description'] = "Comma separated list of domains to add as server alias to the froxlor vhost"; + +$lng['serversettings']['ssl']['tlsv13_cipher_list']['title'] = 'Configure explicit TLSv1.3 ciphers if used'; +$lng['serversettings']['ssl']['tlsv13_cipher_list']['description'] = 'This is a list of ciphers that you want (or don\'t want) to use when talking TLSv1.3. For a list of ciphers and how to include/exclude them, see
the docs for TLSv1.3.

Default value is empty'; +$lng['usersettings']['api_allowed']['title'] = 'Allow API access'; +$lng['usersettings']['api_allowed']['description'] = 'When enabled in the settings, this user can create API keys and access the froxlor API'; +$lng['usersettings']['api_allowed']['notice'] = 'API access is not allowed for your account.'; +$lng['serversettings']['default_sslvhostconf']['title'] = 'Default SSL vHost-settings'; +$lng['serversettings']['includedefault_sslvhostconf'] = 'Include non-SSL vHost-settings in SSL-vHost'; +$lng['admin']['ownsslvhostsettings'] = 'Own SSL vHost-settings'; +$lng['admin']['ipsandports']['ssl_default_vhostconf_domain'] = 'Default SSL vHost-settings for every domain container'; +$lng['customer']['total_diskspace'] = 'Total diskspace (MiB)'; +$lng['admin']['domain_override_tls'] = 'Override system TLS settings'; diff --git a/lng/german.lng.php b/lng/german.lng.php index 791c2513..b8d60d43 100644 --- a/lng/german.lng.php +++ b/lng/german.lng.php @@ -832,7 +832,8 @@ $lng['error']['nopermissionsorinvalidid'] = 'Entweder fehlen Ihnen die nötigen $lng['panel']['view'] = 'ansehen'; $lng['question']['phpsetting_reallydelete'] = 'Wollen Sie diese PHP-Einstellungen wirklich löschen? Alle Domains die diese Einstellungen bis jetzt verwendet haben, werden dann auf die Standardeinstellungen umgestellt.'; $lng['question']['fpmsetting_reallydelete'] = 'Wollen Sie diese PHP-FPM Einstellungen wirklich löschen? Alle PHP Konfigurationen die diese Einstellungen bis jetzt verwendet haben, werden dann auf die Standardeinstellungen umgestellt.'; -$lng['admin']['phpsettings']['addnew'] = 'Neue Konfiguration erstellen'; +$lng['admin']['phpsettings']['addnew'] = 'Neue PHP Konfiguration erstellen'; +$lng['admin']['fpmsettings']['addnew'] = 'Neue PHP Version erstellen'; $lng['error']['phpsettingidwrong'] = 'Eine PHP-Konfiguration mit dieser ID existiert nicht'; $lng['error']['descriptioninvalid'] = 'Der Beschreibungstext ist zu kurz, zu lang oder enthält ungültige Zeichen'; $lng['error']['info'] = 'Info'; @@ -1350,7 +1351,7 @@ $lng['domains']['serveraliasoption_www'] = 'www (www.domain.tld)'; $lng['domains']['serveraliasoption_none'] = 'Kein Alias'; $lng['error']['givendirnotallowed'] = 'Das angegebene Verzeichnis im Feld %s ist nicht erlaubt.'; $lng['serversettings']['ssl']['ssl_cipher_list']['title'] = 'Erlaubte SSL Ciphers festlegen'; -$lng['serversettings']['ssl']['ssl_cipher_list']['description'] = 'Dies ist eine Liste von Ciphers, die genutzt werden sollen (oder auch nicht genutzt werden sollen), wenn eine SSL Verbindung besteht. Eine Liste aller Ciphers und wie diese hinzugefügt/ausgeschlossen werden ist in den Abschnitten "CIPHER LIST FORMAT" und "CIPHER STRINGS" in der man-page für Ciphers zu finden.

Standard-Wert ist:
ECDH+AESGCM:ECDH+AES256:!aNULL:!MD5:!DSS:!DH:!AES128
'; +$lng['serversettings']['ssl']['ssl_cipher_list']['description'] = 'Dies ist eine Liste von Ciphers, die genutzt werden sollen (oder auch nicht genutzt werden sollen), wenn eine SSL Verbindung besteht. Eine Liste aller Ciphers und wie diese hinzugefügt/ausgeschlossen werden ist in den Abschnitten "CIPHER LIST FORMAT" und "CIPHER STRINGS" in der man-page für Ciphers zu finden.

Standard-Wert ist:
ECDH+AESGCM:ECDH+AES256:!aNULL:!MD5:!DSS:!DH:!AES128
'; // Added in Froxlor 0.9.31 $lng['panel']['dashboard'] = 'Dashboard'; @@ -1467,12 +1468,12 @@ $lng['admin']['configfiles']['commands'] = 'Kommandos: $lng['admin']['configfiles']['files'] = 'Konfigurationsdateien: Der Befehl direkt vor dem Textfeld sollte einen Editor mit der Zieldatei öffnen. Der Inhalt kann nun einfach kopiert und in den Editor eingefügt und die Datei gespeichert werden.
Bitte beachten: Das MySQL-Passwort wurde aus Sicherheitsgründen nicht ersetzt. Bitte ersetzen Sie "FROXLOR_MYSQL_PASSWORD" manuell oder nutzen Sie das folgende Formular, um es temporär auf dieser Seite zu setzen. Falls das Passwort vergessen wurde, findet es sich in der Datei "lib/userdata.inc.php".'; $lng['serversettings']['apache_itksupport']['title'] = 'Anpassungen für Apache ITK-MPM verwenden'; $lng['serversettings']['apache_itksupport']['description'] = '
Achtung: Bitte nur verwenden, wenn wirklich Apache itk-mpm verwendet wird, ansonsten wird der Webserver nicht starten.
'; -$lng['integrity_check']['DatabaseCharset'] = 'Characterset der Datenbank (sollte UTF-8 sein)'; -$lng['integrity_check']['DomainIpTable'] = 'IP <‐> Domain Verknüpfung'; -$lng['integrity_check']['SubdomainSslRedirect'] = 'Falsches SSL-redirect Flag bei nicht-SSL Domains'; -$lng['integrity_check']['FroxlorLocalGroupMemberForFcgidPhpFpm'] = 'froxlor-Benutzer in Kunden-Gruppen (für FCGID/php-fpm)'; -$lng['integrity_check']['WebserverGroupMemberForFcgidPhpFpm'] = 'Webserver-Benutzer in Kunden-Gruppen (für FCGID/php-fpm)'; -$lng['integrity_check']['SubdomainLetsencrypt'] = 'Hauptdomains ohne zugewiesenen SSL-Port haben keine Subdomain mit aktiviertem SSL-Redirect'; +$lng['integrity_check']['databaseCharset'] = 'Characterset der Datenbank (sollte UTF-8 sein)'; +$lng['integrity_check']['domainIpTable'] = 'IP <‐> Domain Verknüpfung'; +$lng['integrity_check']['subdomainSslRedirect'] = 'Falsches SSL-redirect Flag bei nicht-SSL Domains'; +$lng['integrity_check']['froxlorLocalGroupMemberForFcgidPhpFpm'] = 'froxlor-Benutzer in Kunden-Gruppen (für FCGID/php-fpm)'; +$lng['integrity_check']['webserverGroupMemberForFcgidPhpFpm'] = 'Webserver-Benutzer in Kunden-Gruppen (für FCGID/php-fpm)'; +$lng['integrity_check']['subdomainLetsencrypt'] = 'Hauptdomains ohne zugewiesenen SSL-Port haben keine Subdomain mit aktiviertem SSL-Redirect'; $lng['admin']['mod_fcgid_umask']['title'] = 'Umask (Standard: 022)'; // Added for let's encrypt @@ -1481,7 +1482,7 @@ $lng['admin']['letsencrypt']['description'] = 'Holt ein kostenloses Zertifikat v $lng['customer']['letsencrypt']['title'] = 'SSL Zertifikat erstellen (Let\'s Encrypt)'; $lng['customer']['letsencrypt']['description'] = 'Holt ein kostenloses Zertifikat von Let\'s Encrypt. Das Zertifikat wird automatisch erstellt und verlängert.
ACHTUNG: Dieses Feature befindet sich noch im Test.'; $lng['error']['sslredirectonlypossiblewithsslipport'] = 'Die Nutzung von Let\'s Encrypt ist nur möglich, wenn die Domain mindestens eine IP/Port - Kombination mit aktiviertem SSL zugewiesen hat.'; -$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt kann in ACME v1 nicht mit Wildcard-Domains umgehen. Bitte den ServerAlias auf WWW setzen oder deaktivieren'; +$lng['error']['nowildcardwithletsencrypt'] = 'Let\'s Encrypt kann mittels ACME Wildcard-Domains nur via DNS validieren, sorry. Bitte den ServerAlias auf WWW setzen oder deaktivieren'; $lng['panel']['letsencrypt'] = 'Benutzt Let\'s encrypt'; $lng['crondesc']['cron_letsencrypt'] = 'Aktualisierung der Let\'s Encrypt Zertifikate'; $lng['serversettings']['letsencryptca']['title'] = "Let's Encrypt Umgebung"; @@ -1500,6 +1501,12 @@ $lng['serversettings']['leenabled']['title'] = "Let's Encrypt verwenden"; $lng['serversettings']['leenabled']['description'] = "Wenn dies aktiviert ist, können Kunden durch Froxlor automatisch generierte und verlängerbare Let's Encrypt SSL-Zertifikate für Domains mit SSL IP/Port nutzen.

Bitte die Webserver-Konfiguration beachten wenn aktiviert, da dieses Feature eine spezielle Konfiguration benötigt."; $lng['domains']['ssl_redirect_temporarilydisabled'] = "
Die SSL-Umleitung ist, während ein neues Let's Encrypt - Zertifikat erstellt wird, temporär deaktiviert. Die Umleitung wird nach der Zertifikatserstellung wieder aktiviert."; +// Added for CAA record support +$lng['serversettings']['caa_entry']['title'] = 'CAA DNS Einträge generieren'; +$lng['serversettings']['caa_entry']['description'] = 'Generiert CAA Einträge automatisch für alle Domains mit aktiviertem SSL und Let\'s Encrypt'; +$lng['serversettings']['caa_entry_custom']['title'] = 'Zusätzliche CAA DNS Einträge'; +$lng['serversettings']['caa_entry_custom']['description'] = 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen,
ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden.

Der Inhalt dieses Feldes wird direkt in die DNS Zone übernommen (eine Zeile pro CAA Record). Wenn Let\'s Encrypt für eine Domain aktiviert wurde und die obige Option aktiviert wurde, wird immer automatisch dieser Eintrag angefügt und muss nicht selber angegeben werden:
0 issue "letsencrypt.org" (Wenn wildcard aktiviert ist, wird statdessen issuewild benutzt).
Um Incident Reporting per Mail zu aktivieren, muss eine iodef Zeile angefügt werden. Ein Beispiel für einen Report an me@example.com wäre:
0 iodef "mailto:me@example.com"

ACHTUNG: Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Die CAA finalen Einträge könnten daher falsch sein!'; + // Autoupdate $lng['admin']['autoupdate'] = 'Auto-Update'; $lng['error']['customized_version'] = 'Es scheint als wäre die Froxlor Installation angepasst worden. Kein Support, sorry.'; @@ -1512,6 +1519,7 @@ $lng['error']['autoupdate_6'] = 'Woops, keine (gültige) Version angegeben für $lng['error']['autoupdate_7'] = 'Das heruntergeladene Archiv konnte nicht gefunden werden :('; $lng['error']['autoupdate_8'] = 'Das Archiv konnte nicht entpackt werden :('; $lng['error']['autoupdate_9'] = 'Die heruntergeladene Datei konnte nicht verifiziert werden. Bitte erneut versuchen zu aktualisieren.'; +$lng['error']['autoupdate_10'] = 'Minimum unterstützte Version von PHP ist 7.0'; $lng['domains']['termination_date'] = 'Kündigungsdatum'; $lng['domains']['termination_date_overview'] = 'gekündigt zum '; @@ -1537,6 +1545,7 @@ $lng['tasks']['backup_customerfiles'] = 'Datensicherung für Kunde %loginname%'; $lng['error']['dns_domain_nodns'] = 'DNS ist für diese Domain nicht aktiviert'; $lng['error']['dns_content_empty'] = 'Keinen Inhalt angegeben'; +$lng['error']['dns_content_invalid'] = 'DNS Eintrag ungültig'; $lng['error']['dns_arec_noipv4'] = 'Keine gültige IP-Adresse für A-Eintrag angegeben'; $lng['error']['dns_aaaarec_noipv6'] = 'Keine gültige IP-Adresse für AAAA-Eintrag angegeben'; $lng['error']['dns_mx_prioempty'] = 'Ungültige MX Priorität angegeben'; @@ -1628,8 +1637,7 @@ $lng['admin']['phpsettings']['activephpconfigs'] = 'In Verwendung für PHP-Konfi $lng['admin']['phpsettingsforsubdomains'] = 'PHP-Config für alle Subdomains übernehmen:'; $lng['serversettings']['phpsettingsforsubdomains']['description'] = 'Wenn ja, wird die gewählte PHP-Config für alle Subdomains übernommen'; $lng['serversettings']['leapiversion']['title'] = "Wählen Sie die Let's Encrypt ACME Implementierung"; -$lng['serversettings']['leapiversion']['description'] = "Wählen Sie zwischen ACME v1 und ACME v2 Implementierung von Let's Encrypt."; -$lng['error']['nowildcardwithletsencryptv2'] = 'Let\'s Encrypt kann in ACME v2 Wildcard-Domains nur via DNS validieren, sorry. Bitte den ServerAlias auf WWW setzen oder deaktivieren'; +$lng['serversettings']['leapiversion']['description'] = "Aktuell unterstützt froxlor lediglich die ACME v2 Implementierung von Let's Encrypt."; $lng['admin']['phpsettings']['pass_authorizationheader'] = 'Füge "-pass-header Authorization" / "CGIPassAuth On" in Vhosts ein'; $lng['serversettings']['ssl']['ssl_protocols']['title'] = 'SSL Protokollversion festlegen'; $lng['serversettings']['ssl']['ssl_protocols']['description'] = 'Dies ist eine Liste von SSL/TLS Protokollversionen die genutzt werden sollen (oder auch nicht genutzt werden sollen), wenn SSL verwendet wird. Hinweis: Ältere Browser sind möglicherweise nicht vollständig zum neusten Protokoll kompatibel.

Standard-Wert ist:
TLSv1, TLSv1.2
'; @@ -1698,6 +1706,7 @@ $lng['panel']['system_is_configured'] = 'Das System ist bereits konfiguriert'; $lng['panel']['settings_before_configuration'] = 'Stelle sicher, dass die Einstellungen angepasst wurden bevor die Dienste konfiguriert werden.'; $lng['panel']['alternative_cmdline_config'] = 'Alternativ, führe den folgenden Befehl als root-Benutzer auf der Shell aus, um die Dienste automatisch zu konfigurieren.'; $lng['tasks']['remove_pdns_domain'] = 'Lösche Domain %s von PowerDNS Datenbank'; +$lng['tasks']['remove_ssl_domain'] = 'Lösche SSL Dateien von Domain %s'; $lng['admin']['novhostcontainer'] = '

Keine der IPs und Ports hat die Option "' . $lng['admin']['ipsandports']['create_vhostcontainer'] . '" aktiviert, einige Einstellungen sind daher nicht verfügbar.'; $lng['serversettings']['errorlog_level']['title'] = 'Ausführlichkeit des Fehlerprotokolls'; $lng['serversettings']['errorlog_level']['description'] = 'Steuert die Ausführlichkeit des Fehlerprotokolls. Voreinstellung ist "warn" bei Apache und "error" bei Nginx.'; @@ -1705,3 +1714,15 @@ $lng['serversettings']['letsencryptecc']['title'] = "ECC / ECDSA Zertifikate aus $lng['serversettings']['letsencryptecc']['description'] = "Wenn eine Schlüsselgröße ausgewählt wird, werden ECC / ECDSA Zertifikate erstellt"; $lng['serversettings']['froxloraliases']['title'] = "Domain Aliase für Froxlor Vhost"; $lng['serversettings']['froxloraliases']['description'] = "Komma getrennte Liste von Domains, welche als Server Alias zum Froxlor Vhost hinzugefügt werden"; + +$lng['serversettings']['ssl']['tlsv13_cipher_list']['title'] = 'Explizite TLSv1.3 Ciphers, wenn genutzt'; +$lng['serversettings']['ssl']['tlsv13_cipher_list']['description'] = 'Dies ist eine Liste von Ciphers, die genutzt werden sollen (oder auch nicht genutzt werden sollen), wenn eine TLSv1.3 Verbindung hergestellt werden soll. Eine Liste aller Ciphers und wie diese hinzugefügt/ausgeschlossen werden ist der Dokumentation für TLSv1.3 zu entnehmen.

Standard-Wert ist leer'; +$lng['usersettings']['api_allowed']['title'] = 'Erlaube API Zugriff'; +$lng['usersettings']['api_allowed']['description'] = 'Wenn in den Einstellungen aktiviert, kann der Benutzer API Schlüssel erstellen und auf die froxlor API Zugreifen'; +$lng['usersettings']['api_allowed']['notice'] = 'API Zugriff ist für dieses Konto deaktiviert.'; +$lng['serversettings']['default_sslvhostconf']['title'] = 'Standard SSL vHost-Einstellungen'; +$lng['serversettings']['includedefault_sslvhostconf'] = 'Nicht-SSL vHost-Einstellungen in SSL-vHost inkludieren'; +$lng['admin']['ownsslvhostsettings'] = 'Eigene SSL vHost-Einstellungen'; +$lng['admin']['ipsandports']['ssl_default_vhostconf_domain'] = 'Standard SSL vHost-Einstellungen für jeden Domain-Container'; +$lng['customer']['total_diskspace'] = 'Gesamtspeicherplatz (MiB)'; +$lng['admin']['domain_override_tls'] = 'Überschreibe System TLS Einstellungen'; diff --git a/lng/italian.lng.php b/lng/italian.lng.php index 90d953cd..fd6e21e6 100644 --- a/lng/italian.lng.php +++ b/lng/italian.lng.php @@ -1571,7 +1571,7 @@ $lng['domains']['serveraliasoption_www'] = 'WWW (www.dominio.tld)'; $lng['domains']['serveraliasoption_none'] = 'Nessun alias'; $lng['error']['givendirnotallowed'] = 'La cartella fornita nel campo %s non è permessa.'; $lng['serversettings']['ssl']['ssl_cipher_list']['title'] = 'Configura le cifrature SSL permesse'; -$lng['serversettings']['ssl']['ssl_cipher_list']['description'] = 'Questa è una lista di cifrature che vuoi (o non vuoi) usare nelle communicazioni SSL. Per una lista delle cifrature e come includerle od escluderle, vedi le sezioni "CIPHER LIST FORMAT" e "CIPHER STRINGS" sulla man-page per le cifrature.

Il valore predefinito è:
ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH
'; +$lng['serversettings']['ssl']['ssl_cipher_list']['description'] = 'Questa è una lista di cifrature che vuoi (o non vuoi) usare nelle communicazioni SSL. Per una lista delle cifrature e come includerle od escluderle, vedi le sezioni "CIPHER LIST FORMAT" e "CIPHER STRINGS" sulla man-page per le cifrature.

Il valore predefinito è:
ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH
'; $lng['panel']['dashboard'] = 'Cruscotto'; $lng['panel']['assigned'] = 'Assegnato'; $lng['panel']['available'] = 'Disponibile'; diff --git a/lng/lng_references.php b/lng/lng_references.php index fade3003..2fdbe385 100644 --- a/lng/lng_references.php +++ b/lng/lng_references.php @@ -37,3 +37,6 @@ $lng['domains']['ipandport_ssl_multi']['description'] = $lng['domains']['ipandpo $lng['success']['noupdatesavail'] = $lng['update']['noupdatesavail']; $lng['error']['autoupdate_3'] = $lng['error']['customized_version']; $lng['menue']['logger']['logger'] = $lng['admin']['loggersystem']; + +$lng['serversettings']['default_sslvhostconf']['description'] = $lng['serversettings']['default_vhostconf']['description']; +$lng['admin']['include_ownvhostsettings'] = $lng['serversettings']['includedefault_sslvhostconf']; diff --git a/phpunit.xml b/phpunit.xml index 4a31f67b..b0ff49e7 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -2,14 +2,13 @@ tests/Global - tests/Froxlor tests/Admins tests/Customers tests/IpsAndPorts @@ -25,17 +24,16 @@ tests/Mysqls tests/PhpAndFpm tests/Traffic + tests/Froxlor - + - + diff --git a/templates/Sparkle/admin/phpconfig/fpmdaemons.tpl b/templates/Sparkle/admin/phpconfig/fpmdaemons.tpl index 693a89d7..2bb01e10 100644 --- a/templates/Sparkle/admin/phpconfig/fpmdaemons.tpl +++ b/templates/Sparkle/admin/phpconfig/fpmdaemons.tpl @@ -11,7 +11,7 @@ $header @@ -32,7 +32,7 @@ $header diff --git a/templates/Sparkle/api_keys/keys_list.tpl b/templates/Sparkle/api_keys/keys_list.tpl index 43cdf15d..2c4407d1 100644 --- a/templates/Sparkle/api_keys/keys_list.tpl +++ b/templates/Sparkle/api_keys/keys_list.tpl @@ -16,6 +16,15 @@ + +
+
+
{$lng['admin']['warning']}
+
{$lng['usersettings']['api_allowed']['notice']}
+
+
+
+
@@ -26,10 +35,12 @@ {$searchcode} + +
@@ -58,11 +69,13 @@ + + $footer diff --git a/templates/Sparkle/assets/js/customers.js b/templates/Sparkle/assets/js/customers.js index 46ff6e1e..40d59bda 100644 --- a/templates/Sparkle/assets/js/customers.js +++ b/templates/Sparkle/assets/js/customers.js @@ -31,7 +31,7 @@ $(document).ready(function() { dataType: "json", success: function(json) { for (var i in json) { - if (i == 'email_imap' || i == 'email_pop3' || i == 'perlenabled' || i == 'phpenabled' || i == 'dnsenabled') { + if (i == 'email_imap' || i == 'email_pop3' || i == 'perlenabled' || i == 'phpenabled' || i == 'dnsenabled' || i == 'logviewenabled') { /** handle checkboxes **/ if (json[i] == 1) { $("input[name='"+i+"']").prop('checked', true); diff --git a/templates/Sparkle/customer/index/index.tpl b/templates/Sparkle/customer/index/index.tpl index f350fa4d..0f128703 100644 --- a/templates/Sparkle/customer/index/index.tpl +++ b/templates/Sparkle/customer/index/index.tpl @@ -7,6 +7,20 @@ $header
+ +
+ +
+ {$lng['customer']['total_diskspace']}
+ + {$userinfo['total_used']} {$lng['panel']['used']}
+ + {$userinfo['diskspace']} {$lng['panel']['available']} + +
+
+
+
diff --git a/templates/Sparkle/header.tpl b/templates/Sparkle/header.tpl index 1b1e9fe8..cfb3f205 100644 --- a/templates/Sparkle/header.tpl +++ b/templates/Sparkle/header.tpl @@ -65,7 +65,7 @@
  • {$lng['menue']['main']['apikeys']}
  • -
  • {$lng['menue']['main']['apihelp']}
  • +
  • {$lng['menue']['main']['apihelp']}
  • diff --git a/templates/Sparkle/misc/ownershiphint.tpl b/templates/Sparkle/misc/ownershiphint.tpl index 9ab32641..ec510e87 100644 --- a/templates/Sparkle/misc/ownershiphint.tpl +++ b/templates/Sparkle/misc/ownershiphint.tpl @@ -25,7 +25,7 @@

     

    This mostly happens due to wrong ownership.
    Try the following command to correct the ownership:

     

    -

    chown -R : <\Froxlor\Froxlor::getInstallDir()>

    +

    chown -R :