Compare commits

...

26 Commits

Author SHA1 Message Date
Michael Kaufmann
d90fb7fa68 fix mysql-pdo check on installation, set version to 2.0.18 for bugfix release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-05-07 10:54:47 +02:00
Michael Kaufmann
4ea8629fcc set version to 2.0.17 for bugfix release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-05-06 22:08:43 +02:00
Michael Kaufmann
9d4ff8698d fix ratelimiting when settings do not exist (yet)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-05-06 22:00:19 +02:00
Michael Kaufmann
b164038846 set version to 2.0.16 for upcoming maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-05-05 21:10:01 +02:00
Michael Kaufmann
5c46960734 fix language mixup for rate-limit-interval setting
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-05-05 13:21:12 +02:00
Michael Kaufmann
a7f4f0c737 output nicer message when hitting rate limit
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-05-04 10:55:34 +02:00
Michael Kaufmann
b64dd501dd fix missing use-statement
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-05-02 10:27:28 +02:00
Michael Kaufmann
1679675aa1 introduce http-request rate-limit; smaller fixes
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-05-02 10:19:53 +02:00
sro0
640466f301 Disable autocomplete on 2FA input element (#1133)
2FA codes change every login. So there is no need to save entered values in browser and suggest them again during future logins.

Co-authored-by: sro0 <>
2023-04-29 09:56:15 +02:00
Michael Kaufmann
9c9771a371 fix generation of current_ips array in Domains-API
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-25 20:09:18 +02:00
Michael Kaufmann
1922b3ce65 set default value for email_quota to settings-default in EmailAccounts.add(); fixes #1132
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-25 19:50:41 +02:00
Michael Kaufmann
83e819908a set default value of 'openbasedir_path' to 0 in SubDomain.add() like we do in Domains.add()
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-25 19:49:09 +02:00
Michael Kaufmann
0924aa644b update dependencies
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-25 19:48:29 +02:00
Lukas Bableck
7711ce1d66 Allow admins to edit openbasedir_path for domains (#1125)
* Add openbasedir_path formfield
* Add openbasedir_path field values to admin_domains page
2023-04-25 19:42:27 +02:00
Michael Kaufmann
7dae63e586 Merge branch 'main' of github.com:Froxlor/Froxlor 2023-04-25 19:40:22 +02:00
Michael Kaufmann
1bcaa45492 add copy-system-details-to-clipboard button on admin dashboard; fixes #1126
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-25 19:36:46 +02:00
Michael Kaufmann
66cb114f0d trigger rebuild of config files after changing only ip-settings in domains
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-25 19:33:52 +02:00
Michael Kaufmann
1c5d60dcfd Add mysql to required extensions 2023-04-23 13:28:33 +02:00
Michael Kaufmann
b6da6356fc Update build-docs.yml 2023-04-23 12:08:19 +02:00
Michael Kaufmann
c09670cc45 make it clearer that the finishing commands have to be exectuted as 'root'; fixes #1128
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-23 11:56:20 +02:00
Michael Kaufmann
464f5b7bed fix adding mysql-server to customers without any prior assigned mysql-server, fixes #1123; fix issues with displaying set value if path-mode is 'dropdown'
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-19 20:58:48 +02:00
Michael Kaufmann
c799235c24 corrected display of special-case titles of settings
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-14 08:23:37 +02:00
Michael Kaufmann
a2860e70a5 strictly check whether field to select is the id or the email-address b/c is cases of email-addresses starting with a digit this is somehow used as value for the id field and return the wrong entity
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-14 08:22:31 +02:00
Michael Kaufmann
95a96d46a6 put php-fpm directives in Directory-directive in apache2; fixes #1120
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-11 09:48:26 +02:00
Michael Kaufmann
81f3dbda31 respect no-try_files setting also in protected directories
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-10 09:33:43 +02:00
Michael Kaufmann
4eb4191843 don't run cron tasks if requirements return non-success; fixes #1122
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2023-04-08 10:49:59 +02:00
36 changed files with 743 additions and 7240 deletions

View File

@@ -11,4 +11,4 @@ jobs:
- env:
GITHUB_TOKEN: ${{ secrets.ORG_GITHUB_TOKEN }}
run: |
gh workflow run --repo Froxlor/Documentation build-and-deploy -f type=tags ref=${{github.ref_name}}
gh workflow run --repo Froxlor/Documentation build-and-deploy.yml -f type=tags ref=${{github.ref_name}}

View File

@@ -138,6 +138,26 @@ return [
'save_method' => 'storeSettingField',
'advanced_mode' => true
],
'system_req_limit_per_interval' => [
'label' => lng('serversettings.req_limit_per_interval'),
'settinggroup' => 'system',
'varname' => 'req_limit_per_interval',
'type' => 'number',
'min' => 30,
'default' => 60,
'save_method' => 'storeSettingField',
'advanced_mode' => true
],
'system_req_limit_interval' => [
'label' => lng('serversettings.req_limit_interval'),
'settinggroup' => 'system',
'varname' => 'req_limit_interval',
'type' => 'number',
'min' => 5,
'default' => 60,
'save_method' => 'storeSettingField',
'advanced_mode' => true
],
'customer_accountprefix' => [
'label' => lng('serversettings.accountprefix'),
'settinggroup' => 'customer',

View File

@@ -282,6 +282,12 @@ if ($page == 'domains' || $page == 'overview') {
}
}
$openbasedir = [
0 => lng('domain.docroot'),
1 => lng('domain.homedir'),
2 => lng('domain.docparent')
];
// create serveralias options
$serveraliasoptions = [
0 => lng('domains.serveraliasoption_wildcard'),
@@ -545,6 +551,12 @@ if ($page == 'domains' || $page == 'overview') {
$result['temporary_ssl_redirect'] = $result['ssl_redirect'];
$result['ssl_redirect'] = ($result['ssl_redirect'] == 0 ? 0 : 1);
$openbasedir = [
0 => lng('domain.docroot'),
1 => lng('domain.homedir'),
2 => lng('domain.docparent')
];
$serveraliasoptions = [
0 => lng('domains.serveraliasoption_wildcard'),
1 => lng('domains.serveraliasoption_www'),

94
composer.lock generated
View File

@@ -499,16 +499,16 @@
},
{
"name": "symfony/console",
"version": "v5.4.21",
"version": "v5.4.22",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "c77433ddc6cdc689caf48065d9ea22ca0853fbd9"
"reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/c77433ddc6cdc689caf48065d9ea22ca0853fbd9",
"reference": "c77433ddc6cdc689caf48065d9ea22ca0853fbd9",
"url": "https://api.github.com/repos/symfony/console/zipball/3cd51fd2e6c461ca678f84d419461281bd87a0a8",
"reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8",
"shasum": ""
},
"require": {
@@ -573,12 +573,12 @@
"homepage": "https://symfony.com",
"keywords": [
"cli",
"command line",
"command-line",
"console",
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.4.21"
"source": "https://github.com/symfony/console/tree/v5.4.22"
},
"funding": [
{
@@ -594,7 +594,7 @@
"type": "tidelift"
}
],
"time": "2023-02-25T16:59:41+00:00"
"time": "2023-03-25T09:27:28+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -1399,16 +1399,16 @@
},
{
"name": "symfony/string",
"version": "v5.4.21",
"version": "v5.4.22",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "edac10d167b78b1d90f46a80320d632de0bd9f2f"
"reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/edac10d167b78b1d90f46a80320d632de0bd9f2f",
"reference": "edac10d167b78b1d90f46a80320d632de0bd9f2f",
"url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62",
"reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62",
"shasum": ""
},
"require": {
@@ -1465,7 +1465,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v5.4.21"
"source": "https://github.com/symfony/string/tree/v5.4.22"
},
"funding": [
{
@@ -1481,7 +1481,7 @@
"type": "tidelift"
}
],
"time": "2023-02-22T08:00:55+00:00"
"time": "2023-03-14T06:11:53+00:00"
},
{
"name": "twig/twig",
@@ -1718,16 +1718,16 @@
},
{
"name": "voku/portable-utf8",
"version": "6.0.12",
"version": "6.0.13",
"source": {
"type": "git",
"url": "https://github.com/voku/portable-utf8.git",
"reference": "db0583727bb17666bbd2ba238c85babb973fd165"
"reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/voku/portable-utf8/zipball/db0583727bb17666bbd2ba238c85babb973fd165",
"reference": "db0583727bb17666bbd2ba238c85babb973fd165",
"url": "https://api.github.com/repos/voku/portable-utf8/zipball/b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
"reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
"shasum": ""
},
"require": {
@@ -1793,7 +1793,7 @@
],
"support": {
"issues": "https://github.com/voku/portable-utf8/issues",
"source": "https://github.com/voku/portable-utf8/tree/6.0.12"
"source": "https://github.com/voku/portable-utf8/tree/6.0.13"
},
"funding": [
{
@@ -1817,7 +1817,7 @@
"type": "tidelift"
}
],
"time": "2023-01-11T12:26:16+00:00"
"time": "2023-03-08T08:35:38+00:00"
}
],
"packages-dev": [
@@ -2030,16 +2030,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.11.0",
"version": "1.11.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"shasum": ""
},
"require": {
@@ -2077,7 +2077,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
},
"funding": [
{
@@ -2085,7 +2085,7 @@
"type": "tidelift"
}
],
"time": "2022-03-03T13:19:32+00:00"
"time": "2023-03-08T13:26:56+00:00"
},
{
"name": "nikic/php-parser",
@@ -2520,16 +2520,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.10.4",
"version": "1.10.14",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "8d39218664b45a4a42d5be66d2b63dcf8c149982"
"reference": "d232901b09e67538e5c86a724be841bea5768a7c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8d39218664b45a4a42d5be66d2b63dcf8c149982",
"reference": "8d39218664b45a4a42d5be66d2b63dcf8c149982",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/d232901b09e67538e5c86a724be841bea5768a7c",
"reference": "d232901b09e67538e5c86a724be841bea5768a7c",
"shasum": ""
},
"require": {
@@ -2558,8 +2558,11 @@
"static analysis"
],
"support": {
"docs": "https://phpstan.org/user-guide/getting-started",
"forum": "https://github.com/phpstan/phpstan/discussions",
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.10.4"
"security": "https://github.com/phpstan/phpstan/security/policy",
"source": "https://github.com/phpstan/phpstan-src"
},
"funding": [
{
@@ -2575,7 +2578,7 @@
"type": "tidelift"
}
],
"time": "2023-03-06T13:39:20+00:00"
"time": "2023-04-19T13:47:27+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -2897,16 +2900,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.6.4",
"version": "9.6.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d"
"reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9125ee085b6d95e78277dc07aa1f46f9e0607b8d",
"reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c993f0d3b0489ffc42ee2fe0bd645af1538a63b2",
"reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2",
"shasum": ""
},
"require": {
@@ -2939,8 +2942,8 @@
"sebastian/version": "^3.0.2"
},
"suggest": {
"ext-soap": "*",
"ext-xdebug": "*"
"ext-soap": "To be able to generate mocks based on WSDL files",
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
"bin": [
"phpunit"
@@ -2979,7 +2982,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.4"
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.7"
},
"funding": [
{
@@ -2995,7 +2999,7 @@
"type": "tidelift"
}
],
"time": "2023-02-27T13:06:37+00:00"
"time": "2023-04-14T08:58:40+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -4161,16 +4165,16 @@
},
{
"name": "symfony/dependency-injection",
"version": "v5.4.21",
"version": "v5.4.22",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "5bc403d96622cf0091abd92c939eadecd4d07f94"
"reference": "e1b7c1432efb4ad1dd89d62906187271e2601ed9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5bc403d96622cf0091abd92c939eadecd4d07f94",
"reference": "5bc403d96622cf0091abd92c939eadecd4d07f94",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e1b7c1432efb4ad1dd89d62906187271e2601ed9",
"reference": "e1b7c1432efb4ad1dd89d62906187271e2601ed9",
"shasum": ""
},
"require": {
@@ -4230,7 +4234,7 @@
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.21"
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.22"
},
"funding": [
{
@@ -4246,7 +4250,7 @@
"type": "tidelift"
}
],
"time": "2023-02-16T09:33:00+00:00"
"time": "2023-03-10T10:02:45+00:00"
},
{
"name": "symfony/filesystem",

View File

@@ -697,8 +697,10 @@ opcache.validate_timestamps'),
('system', 'distribution', ''),
('system', 'update_channel', 'stable'),
('system', 'updatecheck_data', ''),
('system', 'update_notify_last', '2.0.15'),
('system', 'update_notify_last', '2.0.18'),
('system', 'traffictool', 'goaccess'),
('system', 'req_limit_per_interval', 60),
('system', 'req_limit_interval', 60),
('api', 'enabled', '0'),
('api', 'customer_default', '1'),
('2fa', 'enabled', '1'),
@@ -742,8 +744,8 @@ opcache.validate_timestamps'),
('panel', 'logo_overridetheme', '0'),
('panel', 'logo_overridecustom', '0'),
('panel', 'settings_mode', '0'),
('panel', 'version', '2.0.15'),
('panel', 'db_version', '202303150');
('panel', 'version', '2.0.18'),
('panel', 'db_version', '202304260');
DROP TABLE IF EXISTS `panel_tasks`;

View File

@@ -23,6 +23,7 @@
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
use Froxlor\Http\RateLimiter;
use Froxlor\UI\Panel\UI;
use Froxlor\Install\Install;
@@ -62,6 +63,7 @@ require dirname(__DIR__) . '/lib/tables.inc.php';
// init twig
UI::initTwig(true);
UI::sendHeaders();
RateLimiter::run(true);
$installer = new Install();
$installer->handle();

View File

@@ -82,7 +82,7 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` DROP COLUMN `domains_see_all`;");
Update::lastStepStatus(0);
Update::showUpdateStep("Checking for multiple mysql-servers to allow acccess to customers for existing databases");
Update::showUpdateStep("Checking for multiple mysql-servers to allow access to customers for existing databases");
$dbservers_stmt = Database::query("
SELECT `customerid`,
GROUP_CONCAT(DISTINCT `dbserver` SEPARATOR ',') as allowed_mysqlserver
@@ -463,3 +463,27 @@ if (Froxlor::isFroxlorVersion('2.0.14')) {
Update::showUpdateStep("Updating from 2.0.14 to 2.0.15", false);
Froxlor::updateToVersion('2.0.15');
}
if (Froxlor::isDatabaseVersion('202303150')) {
Update::showUpdateStep("Adding new request rate limit settings");
Settings::AddNew("system.req_limit_per_interval", "60");
Settings::AddNew("system.req_limit_interval", "60");
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202304260');
}
if (Froxlor::isFroxlorVersion('2.0.15')) {
Update::showUpdateStep("Updating from 2.0.15 to 2.0.16", false);
Froxlor::updateToVersion('2.0.16');
}
if (Froxlor::isFroxlorVersion('2.0.16')) {
Update::showUpdateStep("Updating from 2.0.16 to 2.0.17", false);
Froxlor::updateToVersion('2.0.17');
}
if (Froxlor::isFroxlorVersion('2.0.18')) {
Update::showUpdateStep("Updating from 2.0.17 to 2.0.18", false);
Froxlor::updateToVersion('2.0.18');
}

View File

@@ -26,6 +26,7 @@
namespace Froxlor\Api;
use Exception;
use Froxlor\Http\RateLimiter;
use Froxlor\Settings;
use voku\helper\AntiXSS;
@@ -52,6 +53,8 @@ class Api
if (Settings::Get('api.enabled') != 1) {
throw new Exception('API is not enabled. Please contact the administrator if you think this is wrong.', 400);
}
RateLimiter::run();
}
/**

View File

@@ -225,6 +225,8 @@ class Domains extends ApiCommand implements ResourceEntity
* optional, whether php is enabled for this domain, default 0 (false)
* @param bool $openbasedir
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
* @param int $openbasedir_path
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
* @param int $phpsettingid
* optional, specify php-configuration that is being used by id, default 1 (system-default)
* @param int $mod_fcgid_starter
@@ -312,6 +314,7 @@ class Domains extends ApiCommand implements ResourceEntity
$documentroot = $this->getParam('documentroot', true, '');
$phpenabled = $this->getBoolParam('phpenabled', true, 0);
$openbasedir = $this->getBoolParam('openbasedir', true, 0);
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
$phpsettingid = $this->getParam('phpsettingid', true, 1);
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, -1);
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, -1);
@@ -530,6 +533,10 @@ class Domains extends ApiCommand implements ResourceEntity
$mod_fcgid_maxrequests = '-1';
}
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
$openbasedir_path = 0;
}
// check non-ssl IP
$ipandports = $this->validateIpAddresses($p_ipandports);
// check ssl IP
@@ -701,6 +708,7 @@ class Domains extends ApiCommand implements ResourceEntity
'caneditdomain' => $caneditdomain,
'phpenabled' => $phpenabled,
'openbasedir' => $openbasedir,
'openbasedir_path' => $openbasedir_path,
'speciallogfile' => $speciallogfile,
'specialsettings' => $specialsettings,
'ssl_specialsettings' => $ssl_specialsettings,
@@ -754,6 +762,7 @@ class Domains extends ApiCommand implements ResourceEntity
`caneditdomain` = :caneditdomain,
`phpenabled` = :phpenabled,
`openbasedir` = :openbasedir,
`openbasedir_path` = :openbasedir_path,
`speciallogfile` = :speciallogfile,
`specialsettings` = :specialsettings,
`ssl_specialsettings` = :ssl_specialsettings,
@@ -1101,6 +1110,8 @@ class Domains extends ApiCommand implements ResourceEntity
* from setting system.apply_phpconfigs_default
* @param bool $openbasedir
* optional, whether to activate openbasedir restriction for this domain, default 0 (false)
* @param int $openbasedir_path
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
* @param int $phpsettingid
* optional, specify php-configuration that is being used by id, default 1 (system-default)
* @param int $mod_fcgid_starter
@@ -1198,6 +1209,7 @@ class Domains extends ApiCommand implements ResourceEntity
$phpenabled = $this->getBoolParam('phpenabled', true, $result['phpenabled']);
$phpfs = $this->getBoolParam('phpsettingsforsubdomains', true, Settings::Get('system.apply_phpconfigs_default'));
$openbasedir = $this->getBoolParam('openbasedir', true, $result['openbasedir']);
$openbasedir_path = $this->getParam('openbasedir_path', true, $result['openbasedir_path']);
$phpsettingid = $this->getParam('phpsettingid', true, $result['phpsettingid']);
$mod_fcgid_starter = $this->getParam('mod_fcgid_starter', true, $result['mod_fcgid_starter']);
$mod_fcgid_maxrequests = $this->getParam('mod_fcgid_maxrequests', true, $result['mod_fcgid_maxrequests']);
@@ -1489,6 +1501,11 @@ class Domains extends ApiCommand implements ResourceEntity
$mod_fcgid_maxrequests = $result['mod_fcgid_maxrequests'];
}
// check changes of openbasedir-path variable
if ($openbasedir_path > 2 && $openbasedir_path < 0) {
$openbasedir_path = 0;
}
// check non-ssl IP
$ipandports = $this->validateIpAddresses($p_ipandports, false, $result['id']);
// check ssl IP
@@ -1634,7 +1651,31 @@ class Domains extends ApiCommand implements ResourceEntity
$wwwserveralias = ($serveraliasoption == '1') ? '1' : '0';
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
if ($documentroot != $result['documentroot'] || $ssl_redirect != $result['ssl_redirect'] || $wwwserveralias != $result['wwwserveralias'] || $iswildcarddomain != $result['iswildcarddomain'] || $phpenabled != $result['phpenabled'] || $openbasedir != $result['openbasedir'] || $phpsettingid != $result['phpsettingid'] || $mod_fcgid_starter != $result['mod_fcgid_starter'] || $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || $specialsettings != $result['specialsettings'] || $ssl_specialsettings != $result['ssl_specialsettings'] || $notryfiles != $result['notryfiles'] || $writeaccesslog != $result['writeaccesslog'] || $writeerrorlog != $result['writeerrorlog'] || $aliasdomain != $result['aliasdomain'] || $issubof != $result['ismainbutsubto'] || $email_only != $result['email_only'] || ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || $letsencrypt != $result['letsencrypt'] || $http2 != $result['http2'] || $hsts_maxage != $result['hsts'] || $hsts_sub != $result['hsts_sub'] || $hsts_preload != $result['hsts_preload'] || $ocsp_stapling != $result['ocsp_stapling']) {
if ($documentroot != $result['documentroot']
|| $ssl_redirect != $result['ssl_redirect']
|| $wwwserveralias != $result['wwwserveralias']
|| $iswildcarddomain != $result['iswildcarddomain']
|| $phpenabled != $result['phpenabled']
|| $openbasedir != $result['openbasedir']
|| $phpsettingid != $result['phpsettingid']
|| $mod_fcgid_starter != $result['mod_fcgid_starter']
|| $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests']
|| $specialsettings != $result['specialsettings']
|| $ssl_specialsettings != $result['ssl_specialsettings']
|| $notryfiles != $result['notryfiles']
|| $writeaccesslog != $result['writeaccesslog']
|| $writeerrorlog != $result['writeerrorlog']
|| $aliasdomain != $result['aliasdomain']
|| $issubof != $result['ismainbutsubto']
|| $email_only != $result['email_only']
|| ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1')
|| $letsencrypt != $result['letsencrypt']
|| $http2 != $result['http2']
|| $hsts_maxage != $result['hsts']
|| $hsts_sub != $result['hsts_sub']
|| $hsts_preload != $result['hsts_preload']
|| $ocsp_stapling != $result['ocsp_stapling']
) {
Cronjob::inserttask(TaskId::REBUILD_VHOST);
}
@@ -1782,7 +1823,8 @@ class Domains extends ApiCommand implements ResourceEntity
$update_data['wwwserveralias'] = $wwwserveralias;
$update_data['iswildcarddomain'] = $iswildcarddomain;
$update_data['phpenabled'] = $phpenabled;
$update_data['openbasedir'] = $openbasedir;
$update_data['openbasedir'] = $openbasedir;;
$update_data['openbasedir_path'] = $openbasedir_path;
$update_data['speciallogfile'] = $speciallogfile;
$update_data['phpsettingid'] = $phpsettingid;
$update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
@@ -1830,6 +1872,7 @@ class Domains extends ApiCommand implements ResourceEntity
`iswildcarddomain` = :iswildcarddomain,
`phpenabled` = :phpenabled,
`openbasedir` = :openbasedir,
`openbasedir_path` = :openbasedir_path,
`speciallogfile` = :speciallogfile,
`phpsettingid` = :phpsettingid,
`mod_fcgid_starter` = :mod_fcgid_starter,
@@ -1865,6 +1908,7 @@ class Domains extends ApiCommand implements ResourceEntity
$_update_data['adminid'] = $adminid;
$_update_data['phpenabled'] = $phpenabled;
$_update_data['openbasedir'] = $openbasedir;
$_update_data['openbasedir_path'] = $openbasedir_path;
$_update_data['mod_fcgid_starter'] = $mod_fcgid_starter;
$_update_data['mod_fcgid_maxrequests'] = $mod_fcgid_maxrequests;
$_update_data['notryfiles'] = $notryfiles;
@@ -1898,6 +1942,7 @@ class Domains extends ApiCommand implements ResourceEntity
`adminid` = :adminid,
`phpenabled` = :phpenabled,
`openbasedir` = :openbasedir,
`openbasedir_path` = :openbasedir_path,
`mod_fcgid_starter` = :mod_fcgid_starter,
`mod_fcgid_maxrequests` = :mod_fcgid_maxrequests,
`notryfiles` = :notryfiles,
@@ -1914,6 +1959,18 @@ class Domains extends ApiCommand implements ResourceEntity
");
Database::pexecute($_update_stmt, $_update_data, true, true);
// get current ip<>domain entries
$ip_sel_stmt = Database::prepare("
SELECT id_ipandports FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
");
Database::pexecute($ip_sel_stmt, [
'id' => $id
], true, true);
$current_ips = [];
while ($cIP = $ip_sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
$current_ips[] = $cIP['id_ipandports'];
}
// Cleanup domain <-> ip mapping
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_DOMAINTOIP . "` WHERE `id_domain` = :id
@@ -1941,6 +1998,12 @@ class Domains extends ApiCommand implements ResourceEntity
}
}
// check ip changes
$all_new_ips = array_merge($ipandports, $ssl_ipandports);
if (count(array_diff($current_ips, $all_new_ips)) != 0 || count(array_diff($all_new_ips, $current_ips)) != 0) {
Cronjob::inserttask(TaskId::REBUILD_VHOST);
}
// Cleanup domain <-> ip mapping for subdomains
$domainidsresult_stmt = Database::prepare("
SELECT `id` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :id

View File

@@ -63,7 +63,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
* @param string $alternative_email
* optional email address to send account information to, default is the account that is being created
* @param int $email_quota
* optional quota if enabled in MB, default 0
* optional quota if enabled in MB, default setting: system.mail_quota
* @param bool $sendinfomail
* optional, sends the welcome message to the new account (needed for creation, without the user won't
* be able to login before any mail is received), default 1 (true)
@@ -85,7 +85,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
$email_password = $this->getParam('email_password');
$alternative_email = $this->getParam('alternative_email', true, '');
$quota = $this->getParam('email_quota', true, 0);
$quota = $this->getParam('email_quota', true, Settings::Get('system.mail_quota') ?? 0);
$sendinfomail = $this->getBoolParam('sendinfomail', true, 1);
// validation

View File

@@ -195,8 +195,8 @@ class Emails extends ApiCommand implements ResourceEntity
FROM `" . TABLE_MAIL_VIRTUAL . "` v
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
AND (v.`id`= :idea OR (v.`email` = :idea OR v.`email_full` = :idea))
");
AND " . (is_numeric($params['idea']) ? "v.`id`= :idea" : "(v.`email` = :idea OR v.`email_full` = :idea)")
);
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'");

View File

@@ -516,7 +516,7 @@ class MysqlServer extends ApiCommand implements ResourceEntity
`allowed_mysqlserver` = :am WHERE `customerid` = :cid
");
while ($customer = $sel_stmt->fetch(PDO::FETCH_ASSOC)) {
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?? '[]'), true);
$allowed_mysqls = json_decode(($customer['allowed_mysqlserver'] ?: '[]'), true);
if (!in_array($dbserver, $allowed_mysqls)) {
$allowed_mysqls[] = $dbserver;
$allowed_mysqls = json_encode($allowed_mysqls);

View File

@@ -62,7 +62,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
* optional, overwrites path value with an URL to generate a redirect, alternatively use the path
* parameter also for URLs
* @param int $openbasedir_path
* optional, either 0 for domains-docroot, 1 for customers-homedir or 2 for parent-directory of domains-docroot
* optional, either 0 for domains-docroot [default], 1 for customers-homedir or 2 for parent-directory of domains-docroot
* @param int $phpsettingid
* optional, php-settings-id, if empty the $domain value is used
* @param int $redirectcode
@@ -104,7 +104,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
$aliasdomain = $this->getParam('alias', true, 0);
$path = $this->getParam('path', true, '');
$url = $this->getParam('url', true, '');
$openbasedir_path = $this->getParam('openbasedir_path', true, 1);
$openbasedir_path = $this->getParam('openbasedir_path', true, 0);
$phpsettingid = $this->getParam('phpsettingid', true, 0);
$redirectcode = $this->getParam('redirectcode', true, Settings::Get('customredirect.default'));
$isemaildomain = $this->getParam('isemaildomain', true, 0);

View File

@@ -122,7 +122,7 @@ class CliCommand extends Command
include_once Froxlor::getInstallDir() . '/lib/tables.inc.php';
define('_CRON_UPDATE', 1);
ob_start([
'this',
$this,
'cleanUpdateOutput'
]);
include_once Froxlor::getInstallDir() . '/install/updatesql.php';

View File

@@ -80,7 +80,7 @@ final class InstallCommand extends Command
$_SERVER['SERVER_NAME'] = $host[0] ?? '';
$ips = [];
exec('hostname -I', $ips);
$ips = explode(" ", $ips[0]);
$ips = explode(" ", $ips[0] ?? "");
// ipv4 address?
$_SERVER['SERVER_ADDR'] = filter_var($ips[0] ?? "", FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? ($ips[0] ?? '') : '';
if (empty($_SERVER['SERVER_ADDR'])) {

View File

@@ -62,6 +62,11 @@ final class MasterCron extends CliCommand
$result = self::SUCCESS;
$result = $this->validateRequirements($input, $output);
if ($result != self::SUCCESS) {
// requirements failed, exit
return $result;
}
$jobs = $input->getArgument('job');
// handle force option
@@ -111,8 +116,8 @@ final class MasterCron extends CliCommand
]);
$this->cronLog->setCronDebugFlag(defined('CRON_DEBUG_FLAG'));
// check whether there are actual tasks to perform by 'tasks'-cron so
// we dont regenerate files unnecessarily
// check whether there are actual tasks to perform by 'tasks'-cron, so
// we don't regenerate files unnecessarily
$tasks_cnt_stmt = Database::query("SELECT COUNT(*) as jobcnt FROM `panel_tasks`");
$tasks_cnt = $tasks_cnt_stmt->fetch(PDO::FETCH_ASSOC);

View File

@@ -126,6 +126,9 @@ class ApacheFcgi extends Apache
// mod_proxy stuff for apache-2.4
if (Settings::Get('system.apache24') == '1' && Settings::Get('phpfpm.use_mod_proxy') == '1') {
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
$filesmatch = $phpconfig['fpm_settings']['limit_extensions'];
$extensions = explode(" ", $filesmatch);
$filesmatch = "";
@@ -141,23 +144,19 @@ class ApacheFcgi extends Apache
$php_options_text .= ' </FilesMatch>' . "\n";
$mypath_dir = new Directory($domain['documentroot']);
// only create the require all granted if there is not active directory-protection
// only create the "require all granted" directive if there is no active directory-protection
// for this path, as this would be the first require and therefore grant all access
if ($mypath_dir->isUserProtected() == false) {
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
if ($phpconfig['pass_authorizationheader'] == '1') {
$php_options_text .= ' CGIPassAuth On' . "\n";
}
$php_options_text .= ' Require all granted' . "\n";
$php_options_text .= ' AllowOverride All' . "\n";
$php_options_text .= ' </Directory>' . "\n";
} elseif ($phpconfig['pass_authorizationheader'] == '1') {
// allow Pass of Authorization header
$php_options_text .= ' <Directory "' . FileDir::makeCorrectDir($domain['documentroot']) . '">' . "\n";
$php_options_text .= ' CGIPassAuth On' . "\n";
$php_options_text .= ' </Directory>' . "\n";
}
$php_options_text .= ' </Directory>' . "\n";
} else {
$addheader = "";
if ($phpconfig['pass_authorizationheader'] == '1') {

View File

@@ -1040,9 +1040,11 @@ class Nginx extends HttpConfigBase
$path_options .= "\t\t" . 'auth_basic_user_file ' . FileDir::makeCorrectFile($single['usrf']) . ';' . "\n";
if ($domain['phpenabled_customer'] == 1 && $domain['phpenabled_vhost'] == '1') {
$path_options .= "\t\t" . 'index index.php index.html index.htm;' . "\n";
if ($domain['notryfiles'] != 1) {
$path_options .= "\t\t" . 'location ~ ^(.+?\.php)(/.*)?$ {' . "\n";
$path_options .= "\t\t\t" . 'try_files ' . $domain['nonexistinguri'] . ' @php;' . "\n";
$path_options .= "\t\t" . '}' . "\n\n";
}
} else {
$path_options .= "\t\t" . 'index index.html index.htm;' . "\n";
}

View File

@@ -447,7 +447,8 @@ class FileDir
$field = [
'type' => 'select',
'select_var' => $_field,
'selected' => $value
'selected' => $value,
'value' => $value
];
} else {
$field = [

View File

@@ -31,10 +31,10 @@ final class Froxlor
{
// Main version variable
const VERSION = '2.0.15';
const VERSION = '2.0.18';
// Database version (YYYYMMDDC where C is a daily counter)
const DBVERSION = '202303150';
const DBVERSION = '202304260';
// Distribution branding-tag (used for Debian etc.)
const BRANDING = '';

View File

@@ -0,0 +1,55 @@
<?php
namespace Froxlor\Http;
use Froxlor\Froxlor;
use Froxlor\Settings;
use Froxlor\UI\Panel\UI;
class RateLimiter
{
private static int $limit_per_interval = 60;
private static int $reset_time = 0;
public static function run(bool $install_mode = false)
{
// default interval = 60 sec
self::$reset_time = time() + 60;
if (!$install_mode) {
self::$limit_per_interval = Settings::Get('system.req_limit_per_interval') ?? 60;
self::$reset_time = time() + Settings::Get('system.req_limit_interval') ?? 60;
}
// Get the remaining requests and reset time from the headers
$remaining = isset($_SESSION['HTTP_X_RATELIMIT_REMAINING']) ? (int)$_SESSION['HTTP_X_RATELIMIT_REMAINING'] : self::$limit_per_interval;
$reset = isset($_SESSION['HTTP_X_RATELIMIT_RESET']) ? (int)$_SESSION['HTTP_X_RATELIMIT_RESET'] : self::$reset_time;
// check if reset time is due
if (time() > $reset) {
$remaining = self::$limit_per_interval;
$reset = self::$reset_time;
}
// If we've hit the limit, return an error
if ($remaining <= 0) {
header('HTTP/1.1 429 Too Many Requests');
header("Retry-After: $reset");
UI::twig()->addGlobal('install_mode', '1');
echo UI::twig()->render('Froxlor/misc/ratelimithint.html.twig', [
'retry' => $reset,
'installdir' => Froxlor::getInstallDir()
]);
die();
}
// Decrement the remaining requests and update the headers
$remaining--;
$_SESSION['HTTP_X_RATELIMIT_REMAINING'] = $remaining;
$_SESSION['HTTP_X_RATELIMIT_RESET'] = $reset;
header("X-RateLimit-Limit: " . self::$limit_per_interval);
header("X-RateLimit-Remaining: " . $remaining);
header("X-RateLimit-Reset: " . $reset);
}
}

View File

@@ -42,7 +42,7 @@ class Install
public $phpVersion;
public $formfield;
public string $requiredVersion = '7.4.0';
public array $requiredExtensions = ['session', 'ctype', 'xml', 'filter', 'posix', 'mbstring', 'curl', 'gmp', 'json', 'gd'];
public array $requiredExtensions = ['session', 'ctype', 'pdo', 'xml', 'filter', 'posix', 'mbstring', 'curl', 'gmp', 'json', 'gd'];
public array $suggestedExtensions = ['bcmath', 'zip'];
public array $suggestions = [];
public array $criticals = [];

View File

@@ -518,9 +518,14 @@ class PhpHelper
$str .= self::tabPrefix($depth, sprintf("'%s' => %s,\n", $key, $value ? 'true' : 'false'));
} elseif (is_int($value)) {
$str .= self::tabPrefix($depth, "'{$key}' => $value,\n");
} else {
if ($key == 'password') {
// special case for passwords (nowdoc)
$str .= self::tabPrefix($depth, "'{$key}' => <<<'EOT'\n{$value}\nEOT,\n");
} else {
$str .= self::tabPrefix($depth, "'{$key}' => '{$value}',\n");
}
}
} else {
$str .= self::parseArrayToString($value, $key, ($depth + 1));
}

View File

@@ -364,6 +364,12 @@ return [
'value' => '1',
'checked' => true
],
'openbasedir_path' => [
'label' => lng('domain.openbasedirpath'),
'type' => 'select',
'select_var' => $openbasedir,
'selected' => 0
],
'phpenabled' => [
'label' => lng('admin.phpenabled'),
'type' => 'checkbox',

View File

@@ -390,6 +390,12 @@ return [
'value' => '1',
'checked' => $result['openbasedir']
],
'openbasedir_path' => [
'label' => lng('domain.openbasedirpath'),
'type' => 'select',
'select_var' => $openbasedir,
'selected' => $result['openbasedir_path']
],
'phpenabled' => [
'label' => lng('admin.phpenabled'),
'type' => 'checkbox',

View File

@@ -57,7 +57,7 @@ return [
'label' => lng('panel.path'),
'desc' => (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescriptionSubdomain').(Settings::Get('system.documentroot_use_default_value') == 1 ? lng('panel.pathDescriptionEx') : '') : null),
'type' => $pathSelect['type'],
'select_var' => $pathSelect['value'],
'select_var' => $pathSelect['select_var'] ?? '',
'selected' => $pathSelect['value'],
'value' => $pathSelect['value'],
'note' => $pathSelect['note'] ?? '',

View File

@@ -52,6 +52,7 @@ require dirname(__DIR__) . '/vendor/autoload.php';
use Froxlor\CurrentUser;
use Froxlor\Froxlor;
use Froxlor\FroxlorLogger;
use Froxlor\Http\RateLimiter;
use Froxlor\Idna\IdnaWrapper;
use Froxlor\Language;
use Froxlor\PhpHelper;
@@ -121,6 +122,7 @@ if (!isset($sql) || !is_array($sql)) {
// send ssl-related headers (later than the others because we need a working database-connection and installation)
UI::sendSslHeaders();
RateLimiter::run();
// create a new idna converter
$idna_convert = new IdnaWrapper();

View File

@@ -2072,6 +2072,14 @@ Vielen Dank, Ihr Administrator',
'toolselect' => 'Traffic Analyzer',
],
'requires_reconfiguration' => 'Änderungen an dieser Einstellungen benötigen unter Umständen eine erneute Konfiguration der folgenden Dienste:<br><strong>%s</strong>',
'req_limit_per_interval' => [
'title' => 'Anzahl der HTTP-Anfragen pro Intervall',
'description' => 'Erlaubte Anzahl von HTTP-Anfragen pro Intervall (siehe unten) auf froxlor, Standard ist "60"',
],
'req_limit_interval' => [
'title' => 'Rate-Limit-Intervall',
'description' => 'Zeit in Sekunden für die maximale Anzahl von HTTP-Anfragen, Standard ist "60".',
],
],
'spf' => [
'use_spf' => 'Aktiviere SPF für Domains?',
@@ -2179,6 +2187,7 @@ Vielen Dank, Ihr Administrator',
'description' => 'Aktualisierung der froxlor Datenbank',
'uc_newinfo' => 'Eine neuere %sVersion ist verfügbar: "%s" (Aktuell installierte Version: %s)',
'notify_subject' => 'Neues Update verfügbar',
'dbupdate_required' => 'Froxlor-Dateien wurden aktualisiert, Datenbank-Aktualisierung notwendig',
],
'usersettings' => [
'custom_notes' => [
@@ -2233,8 +2242,8 @@ Vielen Dank, Ihr Administrator',
'install' => [
'top' => 'Abschluss',
'title' => 'Ein letzter Schritt...',
'description' => 'Der untenstehende Befehl lädt, installiert und konfiguriert die benötigten Dienste auf dem System aufgrund der Angaben die während des Installationsprozessen gesammelt wurden.',
'runcmd' => 'Folgenden Befehl als root-Benutzer in der Shell auf dem Server ausführen:',
'description' => 'Der untenstehende Befehl lädt, installiert und konfiguriert die benötigten Dienste auf dem System aufgrund der Angaben die während des Installationsprozessen gesammelt wurden.<br><br><span class="text-danger">Führe die gezeigten Befehle als <b>root</b> in der Shell/Konsole des Servers aus.</span>',
'runcmd' => 'Folgende Befehle ausführen, um die Installation abzuschließen:',
'manual_config' => 'Ich werden die Dienste manuell konfigurieren, direkt zum Login umleiten',
'waitforconfig' => 'Warte auf Abschluss der Dienstkonfiguration...',
],

View File

@@ -952,7 +952,7 @@ return [
'autoupdate_1' => 'PHP setting allow_url_fopen is disabled. Autoupdate needs this setting to be enabled in php.ini',
'autoupdate_2' => 'PHP zip extension not found, please ensure it is installed and activated',
'autoupdate_4' => 'The froxlor archive could not be stored to the disk :(',
'autoupdate_5' => 'version.froxlor.org returned inacceptable values :(',
'autoupdate_5' => 'version.froxlor.org returned unacceptable values :(',
'autoupdate_6' => 'Whoops, there was no (valid) version given to download :(',
'autoupdate_7' => 'The downloaded archive could not be found :(',
'autoupdate_8' => 'The archive could not be extracted :(',
@@ -2196,6 +2196,14 @@ Yours sincerely, your administrator',
'goaccess' => 'goacccess'
],
'requires_reconfiguration' => 'Changing this settings might require a reconfiguration of the following services:<br><strong>%s</strong>',
'req_limit_per_interval' => [
'title' => 'Number of HTTP requests per interval',
'description' => 'Limit the number of HTTP requests per interval (see below) to froxlor, default is "60"',
],
'req_limit_interval' => [
'title' => 'Rate-limit interval',
'description' => 'Specify the time in seconds for the number of HTTP requests, default is "60"',
],
],
'spf' => [
'use_spf' => 'Activate SPF for domains?',
@@ -2310,6 +2318,7 @@ Yours sincerely, your administrator',
'description' => 'Running database updates for your froxlor installation',
'uc_newinfo' => 'There is a newer %sversion available: "%s" (Your current version is: %s)',
'notify_subject' => 'New update available',
'dbupdate_required' => 'Froxlor files have been updated, database update required',
],
'usersettings' => [
'custom_notes' => [
@@ -2365,8 +2374,8 @@ Yours sincerely, your administrator',
'install' => [
'top' => 'Finish setup',
'title' => 'One last step...',
'description' => 'The command below will download, install and configure required services on your system according to the data you have given in this installation process.',
'runcmd' => 'Run the following command as root-user in your shell on this server:',
'description' => 'The command below will download, install and configure required services on your system according to the data you have given in this installation process.<br><br><span class="text-danger">Be sure to run the following command as <b>root</b> on the server\'s shell/terminal.</span>',
'runcmd' => 'Run the following command to finish the installation:',
'manual_config' => 'I will manually configure the services, just take me to the login',
'waitforconfig' => 'Waiting for services to be configured...',
],

7546
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -42,7 +42,7 @@
<label class="form-check-label" for="switchInstallMode">{% if extended is defined and extended %}{{ lng('install.switchmode_basic') }}{% else %}{{ lng('install.switchmode_advanced') }}{% endif %}</label>
</div>
</div>
<p class="lead">{{ section.description }}</p>
<p class="lead">{{ section.description|raw }}</p>
<hr />
{% import "Froxlor/form/formfields.html.twig" as formfields %}

View File

@@ -12,7 +12,7 @@
<div class="mb-3">
<label for="2fa_code" class="col-form-label">{{ lng('login.2facode') }}</label>
<input class="form-control" type="text" name="2fa_code" id="2fa_code" value="" autofocus required/>
<input class="form-control" type="text" name="2fa_code" id="2fa_code" value="" autocomplete="off" autofocus required/>
</div>
</div>

View File

@@ -0,0 +1,17 @@
{% extends "Froxlor/base.html.twig" %}
{% block content %}
<div class="container my-auto">
<div class="alert alert-warning fade show" role="alert">
<h4 class="alert-heading">
Whoops!
</h4>
<p>It seems like you've hit the rate limit.</p>
<p>Please slow down your requests and retry after {{ retry|date('d.m.Y H:i:s') }}</p>
<hr>
<p class="mt-1 text-center">
<a href="" class="btn btn-primary" title="Reload page">Reload</a>
</p>
</div>
</div>
{% endblock %}

View File

@@ -4,7 +4,7 @@
<h5>
<i class="fa-solid fa-gears"></i>
{{ lng('admin.serversettings') }}
{% if fields._group is defined %}&nbsp;&raquo;&nbsp;{{ fields._group.title }}
{% if fields._group is defined %}&nbsp;&raquo;&nbsp;{{ fields._group.title|raw }}
{% endif %}
</h5>
<span class="text-muted">{{ lng('admin.serversettings_desc') }}</span>
@@ -39,7 +39,7 @@
<i class="{{ field.icon }} fa-2x me-4" style="width: 1em;"></i>
</a>
<div>
{{ field.title }}
{{ field.title|raw }}
{% if field.info is defined and field.info is not empty %}
{{ field.info|raw }}
{% endif %}

View File

@@ -5,4 +5,8 @@ $(function () {
history.back(1);
})
$('#copySysInfo').on('click', function (e) {
e.preventDefault();
navigator.clipboard.writeText($('#ccSysInfo').text().trim());
})
});

View File

@@ -55,6 +55,19 @@
<div class="card-header">
<i class="fa-solid fa-gears me-1"></i>
{{ lng('admin.systemdetails') }}
<div class="float-end">
<button id="copySysInfo" class="btn btn-outline-dark" style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .5rem;" title="Copy to clipboard"><i class="fa-solid fa-copy"></i></button>
</div>
<div id="ccSysInfo" class="d-none">
- Froxlor: {{ call_static('\\Froxlor\\Froxlor', 'getVersionString') }}
- {{ lng('serversettings.update_channel.title') }}: {{ get_setting('system.update_channel') }}
- {{ lng('admin.serversoftware') }}: {{ sysinfo.webserver }}
- {{ lng('admin.phpversion') }}: {{ sysinfo.phpversion }}
- {{ lng('admin.mysqlserverversion') }}: {{ sysinfo.mysqlserverversion }}
- {{ lng('admin.webserverinterface') }}: {{ sysinfo.phpsapi }}
- Kernel: {{ sysinfo.kernel }}
- OS: {{ get_setting('system.distribution') }}
</div>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item d-flex justify-content-between align-items-start">