Compare commits

..

32 Commits
2.2.2 ... 2.1.9

Author SHA1 Message Date
Michael Kaufmann
1347b877a5 set version to 2.1.9 for security bugfix release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-05-03 07:58:15 +02:00
Michael Kaufmann
a862307bce Merge pull request from GHSA-x525-54hf-xr53
* do not log unvalidated user-input to mysql-log (if enabled)

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>

* clean log-text to only allow a subset of special characters

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>

* clean log-text when selecting from database to avoid possible previously added malicious entries

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>

---------

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-05-03 07:56:40 +02:00
Michael Kaufmann
2f03eee9aa add compatibility for mariadb-dump executable instead of mysqldump
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-04-27 10:24:52 +02:00
Michael Kaufmann
f4183b020b set version to 2.1.8 for bugfix release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-29 11:27:32 +01:00
Michael Kaufmann
9a3d88e8c9 fix domains speciallogfile ajax-check/note; improve ajax ip check in admin_ipsandports
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-27 11:08:45 +01:00
Michael Kaufmann
c9460fd58f also add logfiles to virtual-host if it's a redirect
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-27 10:17:48 +01:00
Michael Kaufmann
6ef532b470 fix missing csrf tokens for some ajax requests
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-27 10:17:37 +01:00
Wiebe Cazemier
5909401cdd Fix "expires" option cannot have a year greater than 9999 (#1246)
This fixes the exception: '"expires" option cannot have a year greater
than 9999', which happens on upgrade from Debian 11 to 12. The session
timeout in the DB is 9999999999999, so we constrain the value.
2024-03-25 08:22:00 +01:00
Michael Kaufmann
809e8ef45b set version to 2.1.7 for maintenance release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-17 08:30:38 +01:00
Michael Kaufmann
0a091a99e8 wrap SetHandler to php-fpm in file-exists check, as we do for customer-domains already
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-17 08:24:56 +01:00
dependabot[bot]
e299fbe665 Bump follow-redirects from 1.15.4 to 1.15.6 (#1244)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.4 to 1.15.6.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-17 08:15:09 +01:00
Michael Kaufmann
67e8b622d8 correctly save pass_authorizationheader flag for php-configs if FCGID is used; correctly add 'FcgidPassHeader' for froxlor-vhost itself if set
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-17 08:13:24 +01:00
Michael Kaufmann
ce509273d4 correctly validate if a symlink is within the customers home-directory if it's not an absolute path; fixes #1242
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-08 09:23:58 +01:00
Michael Kaufmann
bcf588a2e4 correctly disabled ssl-related settings when domain update sets ssl-enbled flag to false; fixes #1241
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-04 16:49:20 +01:00
Michael Kaufmann
f08d540e66 dont escape panel_password_special_char field
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-03 10:37:42 +01:00
Michael Kaufmann
e06db3d8c5 re-trigger vhost regeneration on tmp. ssl-redirect
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-03-03 10:36:41 +01:00
Michael Kaufmann
c5c04ebe9c fix adding/editing domains as customer when php is not enabled for the domain; don't add custom-vhost-content to deactivated domain-vhosts
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-02-05 22:10:33 +01:00
Michael Kaufmann
c9faa38f6c fix regression bug in 'incorrect top-5 customers' sorting in traffic-overview which leads to incorrect customer-links due to wrong indexing in the array; fixes #1236
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-02-04 20:34:48 +01:00
Michael Kaufmann
c188f047dc backport UI/Callback fixes from 2.2-dev (main); fixes #1235
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-02-04 18:53:12 +01:00
Michael Kaufmann
775d50306c set version to 2.1.6 for bugfix/regression release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-02-03 14:22:33 +01:00
Michael Kaufmann
3821144c3b also fix unittests accordingly
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-02-03 14:08:23 +01:00
Michael Kaufmann
a1da70c221 fix password crypt hash being always evaluated to argon2i as the case always returns true if PASSWORD_ARGON2I is defined but the froxlor setting might be set to another hash leading to a useless password
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-02-03 13:49:43 +01:00
Michael Kaufmann
bb2db0fed0 set version to 2.1.5 for bugfix release
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-02-02 11:18:48 +01:00
Michael Kaufmann
9680f24640 fix check for allowed_phpconfigs if using mod_php when adding/editing a customer
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-01-30 19:32:10 +01:00
Michael Kaufmann
c732fbd81b set correct channel for update-check if switching from apt-installed stable/testing to nightly
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-01-26 13:57:51 +01:00
Michael Kaufmann
7980b8d14d create empty dns-server config if no (dns-enabled) domain is determined; fixes #1230
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-01-24 08:39:16 +01:00
Michael Kaufmann
13e88f5b47 fix incorrect top-5 customers in traffic overview for admins; show manual update command if webupdate is disabled
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-01-19 09:22:12 +01:00
sro0
031596301b Check for argon2 support before using constant PASSWORD_ARGON2X (#1228) 2024-01-16 21:40:03 +01:00
Michael Kaufmann
b34ab45746 disable pam auth in dovecot for debian bookworm (like the other distros do it)
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-01-07 09:06:15 +01:00
Michael Kaufmann
dbf83c6f24 build nightly only from main branch #2
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-01-06 15:01:52 +01:00
Michael Kaufmann
4cb974839c build nightly only from main branch
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-01-06 14:54:23 +01:00
Michael Kaufmann
1fa714ef2c add v2.1 branch to security md as currently supported as well as update main-branch version; add field.disabled attribute to formfield-input-template
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
2024-01-06 14:48:41 +01:00
157 changed files with 3299 additions and 7052 deletions

View File

@@ -12,7 +12,7 @@ jobs:
mariadb-version: [ 10.11, 10.5 ]
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2
@@ -57,7 +57,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup PHP with PECL extension
uses: shivammathur/setup-php@v2
@@ -70,7 +70,7 @@ jobs:
run: composer install --no-dev
- name: Install Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: '20.x'
@@ -119,7 +119,7 @@ jobs:
mv froxlor-nightly.${{steps.vars.outputs.sha_short}}.zip.sha256 dist/
- name: Deploy nightly to server
uses: easingthemes/ssh-deploy@main
uses: easingthemes/ssh-deploy@v3.4.3
env:
ARGS: "-rltDzvO --chown=${{ secrets.WEB_USER }}:${{ secrets.WEB_USER }}"
SOURCE: "dist/"

View File

@@ -12,7 +12,7 @@ jobs:
mysql-version: [8.0, 5.7]
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2
@@ -39,7 +39,16 @@ jobs:
- name: Wait for database
run: sleep 15
- name: Setup database
- name: Setup database (8.0)
if: matrix.mysql-version == '8.0'
run: |
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "CREATE USER 'froxlor010'@'%' IDENTIFIED WITH mysql_native_password BY 'fr0xl0r.TravisCI';"
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI -e "GRANT ALL ON froxlor010.* TO 'froxlor010'@'%';"
php -r "echo include('install/froxlor.sql.php');" > /tmp/froxlor.sql
mysql -h 127.0.0.1 --protocol=TCP -u root -pfr0xl0r.TravisCI froxlor010 < /tmp/froxlor.sql
- name: Setup database (5.7)
if: matrix.mysql-version == '5.7'
run: |
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'@'%';"

View File

@@ -33,7 +33,6 @@ use Froxlor\FroxlorLogger;
use Froxlor\FroxlorTwoFactorAuth;
use Froxlor\Settings;
use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response;
use Froxlor\PhpHelper;
use Froxlor\User;
@@ -64,7 +63,7 @@ if ($action == 'delete') {
]);
Response::standardSuccess('2fa.2fa_removed');
} elseif ($action == 'preadd') {
$type = Request::post('type_2fa', '0');
$type = isset($_POST['type_2fa']) ? $_POST['type_2fa'] : '0';
$data = "";
if ($type > 0) {
@@ -108,9 +107,9 @@ if ($action == 'delete') {
Response::dynamicError('Select one of the possible values for 2FA');
}
} elseif ($action == 'add') {
$type = Request::post('type_2fa', '0');
$data = Request::post('data_2fa', '');
$code = Request::post('codevalidation', '');
$type = isset($_POST['type_2fa']) ? $_POST['type_2fa'] : '0';
$data = isset($_POST['data_2fa']) ? $_POST['data_2fa'] : '';
$code = isset($_POST['codevalidation']) ? $_POST['codevalidation'] : '';
// validate
$result = $tfa->verifyCode($data, $code, 3);

View File

@@ -58,17 +58,17 @@ https://files.froxlor.org/releases/froxlor-latest.tar.gz [MD5](https://files.fro
#### Debian
```
apt -y install apt-transport-https lsb-release ca-certificates curl gnupg
apt-get -y install apt-transport-https lsb-release ca-certificates curl
curl -sSLo /usr/share/keyrings/deb.froxlor.org-froxlor.gpg https://deb.froxlor.org/froxlor.gpg
sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.froxlor.org-froxlor.gpg] https://deb.froxlor.org/debian $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list'
echo sh -c '"deb [signed-by=/usr/share/keyrings/deb.froxlor.org-froxlor.gpg] https://deb.froxlor.org/debian $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list'
```
#### Ubuntu
```
apt -y install apt-transport-https lsb-release ca-certificates curl gnupg
apt-get -y install apt-transport-https lsb-release ca-certificates curl
curl -sSLo /usr/share/keyrings/deb.froxlor.org-froxlor.gpg https://deb.froxlor.org/froxlor.gpg
sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.froxlor.org-froxlor.gpg] https://deb.froxlor.org/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list'
echo sh -c '"deb [signed-by=/usr/share/keyrings/deb.froxlor.org-froxlor.gpg] https://deb.froxlor.org/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/froxlor.list'
```
## Contributing

View File

@@ -180,6 +180,18 @@ return [
'default' => true,
'save_method' => 'storeSettingField'
],
'system_httpuser' => [
'settinggroup' => 'system',
'varname' => 'httpuser',
'type' => 'hidden',
'default' => 'www-data'
],
'system_httpgroup' => [
'settinggroup' => 'system',
'varname' => 'httpgroup',
'type' => 'hidden',
'default' => 'www-data'
],
'system_report_enable' => [
'label' => lng('serversettings.report.report'),
'settinggroup' => 'system',

View File

@@ -176,7 +176,6 @@ return [
'varname' => 'mod_fcgid_httpuser',
'type' => 'text',
'default' => 'froxlorlocal',
'string_emptyallowed' => false,
'save_method' => 'storeSettingWebserverFcgidFpmUser',
'websrv_avail' => [
'apache2'
@@ -194,7 +193,6 @@ return [
'type' => 'text',
'default' => 'froxlorlocal',
'save_method' => 'storeSettingField',
'string_emptyallowed' => false,
'websrv_avail' => [
'apache2'
],
@@ -245,7 +243,6 @@ return [
'varname' => 'vhost_httpuser',
'type' => 'text',
'default' => 'froxlorlocal',
'string_emptyallowed' => false,
'save_method' => 'storeSettingWebserverFcgidFpmUser',
'visible' => Settings::Get('phpfpm.enabled') && call_user_func([
'\Froxlor\Settings\FroxlorVhostSettings',
@@ -259,7 +256,6 @@ return [
'varname' => 'vhost_httpgroup',
'type' => 'text',
'default' => 'froxlorlocal',
'string_emptyallowed' => false,
'save_method' => 'storeSettingField',
'visible' => Settings::Get('phpfpm.enabled') && call_user_func([
'\Froxlor\Settings\FroxlorVhostSettings',

View File

@@ -251,37 +251,8 @@ return [
'string_type' => 'validate_ip',
'string_emptyallowed' => true,
'default' => '',
'save_method' => 'storeSettingField',
'advanced_mode' => true
],
'system_le_renew_services' => [
'label' => lng('serversettings.le_renew_services'),
'settinggroup' => 'system',
'varname' => 'le_renew_services',
'type' => 'select',
'default' => '',
'select_mode' => 'multiple',
'option_emptyallowed' => true,
'select_var' => [
'' => lng('panel.none_value'),
'postfix' => 'postfix (smtp)',
'dovecot' => 'dovecot (imap/pop3)',
'proftpd' => 'proftpd (ftp)',
],
'save_method' => 'storeSettingField',
'advanced_mode' => true
],
'system_le_renew_hook' => [
'label' => lng('serversettings.le_renew_hook'),
'settinggroup' => 'system',
'varname' => 'le_renew_hook',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
'default' => 'systemctl restart postfix dovecot proftpd',
'save_method' => 'storeSettingField',
'advanced_mode' => true,
'required_otp' => true
],
'save_method' => 'storeSettingField'
]
]
]
]

View File

@@ -1,111 +0,0 @@
<?php
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can also view it online at
* https://files.froxlor.org/misc/COPYING.txt
*
* @copyright the authors
* @author Froxlor team <team@froxlor.org>
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
return [
'groups' => [
'antispam' => [
'title' => lng('admin.antispam_settings'),
'icon' => 'fa-solid fa-clipboard-check',
'fields' => [
'antispam_activated' => [
'label' => lng('antispam.activated'),
'settinggroup' => 'antispam',
'varname' => 'activated',
'type' => 'checkbox',
'default' => true,
'overview_option' => true,
'save_method' => 'storeSettingFieldInsertAntispamTask',
],
'antispam_config_file' => [
'label' => lng('antispam.config_file'),
'settinggroup' => 'antispam',
'varname' => 'config_file',
'type' => 'text',
'string_type' => 'file',
'default' => '/etc/rspamd/local.d/froxlor_settings.conf',
'save_method' => 'storeSettingFieldInsertAntispamTask',
'requires_reconf' => ['antispam']
],
'antispam_reload_command' => [
'label' => lng('antispam.reload_command'),
'settinggroup' => 'antispam',
'varname' => 'reload_command',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
'default' => 'service rspamd restart',
'save_method' => 'storeSettingField',
'required_otp' => true
],
'antispam_dkim_keylength' => [
'label' => lng('antispam.dkim_keylength'),
'settinggroup' => 'antispam',
'varname' => 'dkim_keylength',
'type' => 'select',
'default' => '1024',
'select_var' => [
'1024' => '1024 Bit',
'2048' => '2048 Bit'
],
'save_method' => 'storeSettingFieldInsertBindTask',
'advanced_mode' => true,
],
'spf_use_spf' => [
'label' => lng('spf.use_spf'),
'settinggroup' => 'spf',
'varname' => 'use_spf',
'type' => 'checkbox',
'default' => false,
'save_method' => 'storeSettingField',
],
'spf_spf_entry' => [
'label' => lng('spf.spf_entry'),
'settinggroup' => 'spf',
'varname' => 'spf_entry',
'type' => 'text',
'string_regexp' => '/^v=spf[a-z0-9:~?\s.-]+$/i',
'default' => 'v=spf1 a mx -all',
'save_method' => 'storeSettingField'
],
'dmarc_use_dmarc' => [
'label' => lng('dmarc.use_dmarc'),
'settinggroup' => 'dmarc',
'varname' => 'use_dmarc',
'type' => 'checkbox',
'default' => false,
'save_method' => 'storeSettingField',
],
'dmarc_dmarc_entry' => [
'label' => lng('dmarc.dmarc_entry'),
'settinggroup' => 'dmarc',
'varname' => 'dmarc_entry',
'type' => 'text',
'string_regexp' => '/^v=dmarc1(.+)$/i',
'default' => 'v=DMARC1; p=none;',
'save_method' => 'storeSettingField'
]
]
]
]
];

View File

@@ -0,0 +1,146 @@
<?php
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can also view it online at
* https://files.froxlor.org/misc/COPYING.txt
*
* @copyright the authors
* @author Froxlor team <team@froxlor.org>
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
use Froxlor\Settings;
return [
'groups' => [
'dkim' => [
'title' => lng('admin.dkimsettings'),
'icon' => 'fa-solid fa-fingerprint',
'fields' => [
'dkim_use_dkim' => [
'label' => lng('dkim.use_dkim'),
'settinggroup' => 'dkim',
'varname' => 'use_dkim',
'type' => 'checkbox',
'default' => false,
'save_method' => 'storeSettingFieldInsertBindTask',
'overview_option' => true
],
'dkim_dkim_prefix' => [
'label' => lng('dkim.dkim_prefix'),
'settinggroup' => 'dkim',
'varname' => 'dkim_prefix',
'type' => 'text',
'string_type' => 'dir',
'default' => '/etc/postfix/dkim/',
'save_method' => 'storeSettingField'
],
'dkim_privkeysuffix' => [
'label' => lng('dkim.privkeysuffix'),
'settinggroup' => 'dkim',
'varname' => 'privkeysuffix',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\._]+$/i',
'default' => '.priv',
'save_method' => 'storeSettingField',
'advanced_mode' => true
],
'dkim_dkim_domains' => [
'label' => lng('dkim.dkim_domains'),
'settinggroup' => 'dkim',
'varname' => 'dkim_domains',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\._]+$/i',
'default' => 'domains',
'save_method' => 'storeSettingField'
],
'dkim_dkim_dkimkeys' => [
'label' => lng('dkim.dkim_dkimkeys'),
'settinggroup' => 'dkim',
'varname' => 'dkim_dkimkeys',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\._]+$/i',
'default' => 'dkim-keys.conf',
'save_method' => 'storeSettingField'
],
'dkim_dkim_algorithm' => [
'label' => lng('dkim.dkim_algorithm'),
'settinggroup' => 'dkim',
'varname' => 'dkim_algorithm',
'type' => 'select',
'default' => 'all',
'select_mode' => 'multiple',
'select_var' => [
'all' => 'All',
'sha1' => 'SHA1',
'sha256' => 'SHA256'
],
'save_method' => 'storeSettingFieldInsertBindTask',
'advanced_mode' => true
],
'dkim_dkim_servicetype' => [
'label' => lng('dkim.dkim_servicetype'),
'settinggroup' => 'dkim',
'varname' => 'dkim_servicetype',
'type' => 'select',
'default' => '0',
'select_var' => [
'0' => 'All',
'1' => 'E-Mail'
],
'save_method' => 'storeSettingFieldInsertBindTask',
'advanced_mode' => true
],
'dkim_dkim_keylength' => [
'label' => [
'title' => lng('dkim.dkim_keylength.title'),
'description' => lng('dkim.dkim_keylength.description', [Settings::Get('dkim.dkim_prefix')])
],
'settinggroup' => 'dkim',
'varname' => 'dkim_keylength',
'type' => 'select',
'default' => '1024',
'select_var' => [
'1024' => '1024 Bit',
'2048' => '2048 Bit'
],
'save_method' => 'storeSettingFieldInsertBindTask'
],
'dkim_dkim_notes' => [
'label' => lng('dkim.dkim_notes'),
'settinggroup' => 'dkim',
'varname' => 'dkim_notes',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\._]+$/i',
'default' => '',
'save_method' => 'storeSettingFieldInsertBindTask',
'advanced_mode' => true
],
'dkim_dkimrestart_command' => [
'label' => lng('dkim.dkimrestart_command'),
'settinggroup' => 'dkim',
'varname' => 'dkimrestart_command',
'type' => 'text',
'string_regexp' => '/^[a-z0-9\/\._\- ]+$/i',
'default' => '/etc/init.d/dkim-filter restart',
'save_method' => 'storeSettingField',
'required_otp' => true
]
]
]
]
];

View File

@@ -23,26 +23,31 @@
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
use Froxlor\Install\Update;
$preconfig = [
'title' => '2.2.x updates',
'fields' => []
return [
'groups' => [
'spf' => [
'title' => lng('admin.spfsettings'),
'icon' => 'fa-solid fa-clipboard-check',
'fields' => [
'spf_use_spf' => [
'label' => lng('spf.use_spf'),
'settinggroup' => 'spf',
'varname' => 'use_spf',
'type' => 'checkbox',
'default' => false,
'save_method' => 'storeSettingField',
'overview_option' => true
],
'spf_spf_entry' => [
'label' => lng('spf.spf_entry'),
'settinggroup' => 'spf',
'varname' => 'spf_entry',
'type' => 'text',
'string_regexp' => '/^v=spf[a-z0-9:~?\s.-]+$/i',
'default' => 'v=spf1 a mx -all',
'save_method' => 'storeSettingField'
]
]
]
]
];
$return = [];
if (Update::versionInUpdate($current_version, '2.2.0-dev1')) {
$has_preconfig = true;
$description = 'Froxlor now features antispam configurations using rspamd. Would you like to enable the antispam feature (required re-configuration of services)?<br><strong>ATTENTION:</strong> When not enabled and the former DomainKey feature was used, keep in mind that all existing domainkeys for all domain are being removed and the dkim-flag disabled for the domains.';
$question = '<strong>Enable antispam (recommended)</strong>&nbsp;';
$return['antispam_activated'] = [
'type' => 'checkbox',
'value' => 1,
'checked' => 0,
'label' => $question,
'prior_infotext' => $description
];
}
$preconfig['fields'] = $return;
return $preconfig;

View File

@@ -106,7 +106,7 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin
Response::standardError('youcantdeleteyourself');
}
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
Admins::getLocal($userinfo, [
'id' => $id
])->delete();
@@ -122,9 +122,9 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin
}
}
} elseif ($action == 'add') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Admins::getLocal($userinfo, Request::postAll())->add();
Admins::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -159,9 +159,9 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin
$result = json_decode($json_result, true)['data'];
if ($result['loginname'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Admins::getLocal($userinfo, Request::postAll())->update();
Admins::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -33,7 +33,6 @@
use Froxlor\FroxlorLogger;
use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response;
use Froxlor\UI\HTML;
@@ -43,7 +42,7 @@ require __DIR__ . '/lib/init.php';
$horizontal_bar_size = 950; // 1280px window width
if ($action == 'delete' && function_exists('apcu_clear_cache') && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') {
if ($_POST['send'] == 'send') {
apcu_clear_cache();
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "cleared APCu cache");
header('Location: ' . $linker->getLink([
@@ -118,7 +117,7 @@ if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') {
'uptime' => duration($cache['start_time'])
];
$overview['mem_used_percentage'] = number_format(($overview['mem_used'] / $overview['mem_size']) * 100, 1);
$overview['mem_used_percentage'] = number_format(($overview['mem_used'] / $overview['mem_avail']) * 100, 1);
$overview['num_hits_percentage'] = number_format(($overview['num_hits'] / $overview['num_hits_and_misses']) * 100,
1);
$overview['num_misses_percentage'] = number_format(($overview['num_misses'] / $overview['num_hits_and_misses']) * 100,

View File

@@ -32,7 +32,6 @@ use Froxlor\FileDir;
use Froxlor\Install\AutoUpdate;
use Froxlor\Settings;
use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response;
if ($page != 'error') {
@@ -111,7 +110,7 @@ if ($page == 'overview') {
} // download the new archive
elseif ($page == 'getdownload') {
// retrieve the new version from the form
$newversion = Request::post('newversion');
$newversion = isset($_POST['newversion']) ? $_POST['newversion'] : null;
$result = 6;
// valid?
@@ -131,8 +130,8 @@ elseif ($page == 'getdownload') {
]);
} // extract and install new version
elseif ($page == 'extract') {
if (Request::post('send') == 'send') {
$toExtract = Request::post('archive');
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$toExtract = isset($_POST['archive']) ? $_POST['archive'] : null;
$localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract);
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "Extracting " . $localArchive . " to " . Froxlor::getInstallDir());
$result = AutoUpdate::extractZip($localArchive);
@@ -146,7 +145,7 @@ elseif ($page == 'extract') {
// redirect to update-page
Response::redirectTo('admin_updates.php');
} else {
$toExtract = Request::get('archive');
$toExtract = isset($_GET['archive']) ? $_GET['archive'] : null;
$localArchive = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/updates/' . $toExtract);
}
@@ -193,7 +192,7 @@ elseif ($page == 'extract') {
} // display error
elseif ($page == 'error') {
// retrieve error-number via url-parameter
$errno = Request::get('errno', 0);
$errno = isset($_GET['errno']) ? (int)$_GET['errno'] : 0;
// 2 = no Zlib
// 3 = custom version detected

View File

@@ -93,14 +93,14 @@ if ($userinfo['change_serversettings'] == '1') {
asort($distributions_select);
}
if ($distribution != "" && !empty(Request::post('finish'))) {
$valid_keys = ['http', 'dns', 'smtp', 'mail', 'antispam', 'ftp', 'system', 'distro'];
if ($distribution != "" && isset($_POST['finish'])) {
$valid_keys = ['http', 'dns', 'smtp', 'mail', 'ftp', 'system', 'distro'];
unset($_POST['finish']);
unset($_POST['csrf_token']);
$params = Request::postAll();
$params = $_POST;
$params['distro'] = $distribution;
$params['system'] = [];
foreach (Request::post('system', []) as $sysdaemon) {
foreach ($_POST['system'] as $sysdaemon) {
$params['system'][] = $sysdaemon;
}
// validate params

View File

@@ -68,9 +68,9 @@ if (($page == 'cronjobs' || $page == 'overview') && $userinfo['change_serversett
}
$result = json_decode($json_result, true)['data'];
if ($result['cronfile'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Cronjobs::getLocal($userinfo, Request::postAll())->update();
Cronjobs::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -98,7 +98,7 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "switched user and is now '" . $destination_user . "'");
$target = Request::get('target', 'index');
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
$redirect = "customer_" . $target . ".php";
if (!file_exists(Froxlor::getInstallDir() . "/" . $redirect)) {
$redirect = "customer_index.php";
@@ -119,7 +119,7 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
}
$result = json_decode($json_result, true)['data'];
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
$json_result = Customers::getLocal($userinfo, [
'id' => $id
@@ -147,11 +147,11 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
}
$result = json_decode($json_result, true)['data'];
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
$json_result = Customers::getLocal($userinfo, [
'id' => $id,
'delete_userfiles' => Request::post('delete_userfiles', 0)
'delete_userfiles' => (isset($_POST['delete_userfiles']) ? (int)$_POST['delete_userfiles'] : 0)
])->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
@@ -167,9 +167,9 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
], $result['loginname']);
}
} elseif ($action == 'add') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Customers::getLocal($userinfo, Request::postAll())->add();
Customers::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -243,9 +243,9 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != '
$result = json_decode($json_result, true)['data'];
if ($result['loginname'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Customers::getLocal($userinfo, Request::postAll())->update();
Customers::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -100,9 +100,9 @@ if ($page == 'domains' || $page == 'overview') {
]);
if ($result['domain'] != '') {
if (Request::post('send') == 'send' && $alias_check['count'] == 0) {
if (isset($_POST['send']) && $_POST['send'] == 'send' && $alias_check['count'] == 0) {
try {
Domains::getLocal($userinfo, Request::postAll())->delete();
Domains::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -113,7 +113,7 @@ if ($page == 'domains' || $page == 'overview') {
} elseif ($alias_check['count'] > 0) {
Response::standardError('domains_cantdeletedomainwithaliases');
} else {
HTML::askYesNoWithCheckbox('admin_domain_reallydelete', 'admin_customer_alsoremovemail', $filename, [
HTML::askYesNo('admin_domain_reallydelete', $filename, [
'id' => $id,
'page' => $page,
'action' => $action
@@ -121,9 +121,9 @@ if ($page == 'domains' || $page == 'overview') {
}
}
} elseif ($action == 'add') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Domains::getLocal($userinfo, Request::postAll())->add();
Domains::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -355,13 +355,13 @@ if ($page == 'domains' || $page == 'overview') {
$usedips[] = $ipsresultrow['id_ipandports'];
}
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
// remove ssl ip/ports if set is empty
if (empty(Request::post('ssl_ipandport'))) {
if (!isset($_POST['ssl_ipandport']) || empty($_POST['ssl_ipandport'])) {
$_POST['remove_ssl_ipandport'] = true;
}
Domains::getLocal($userinfo, Request::postAll())->update();
Domains::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -572,13 +572,13 @@ if ($page == 'domains' || $page == 'overview') {
}
}
} elseif ($action == 'jqGetCustomerPHPConfigs') {
$customerid = intval(Request::post('customerid'));
$customerid = intval($_POST['customerid']);
$allowed_phpconfigs = Customer::getCustomerDetail($customerid, 'allowed_phpconfigs');
echo !empty($allowed_phpconfigs) ? $allowed_phpconfigs : json_encode([]);
exit();
} elseif ($action == 'jqSpeciallogfileNote') {
$domainid = intval(Request::post('id'));
$newval = intval(Request::post('newval'));
$domainid = intval($_POST['id']);
$newval = intval($_POST['newval']);
try {
$json_result = Domains::getLocal($userinfo, [
'id' => $domainid
@@ -594,9 +594,9 @@ if ($page == 'domains' || $page == 'overview') {
echo 0;
exit();
} elseif ($action == 'import') {
if (Request::post('send') == 'send') {
$separator = Validate::validate(Request::post('separator'), 'separator');
$offset = (int)Validate::validate(Request::post('offset'), 'offset', "/[0-9]/i");
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$separator = Validate::validate($_POST['separator'], 'separator');
$offset = (int)Validate::validate($_POST['offset'], 'offset', "/[0-9]/i");
$file_name = $_FILES['file']['tmp_name'];
@@ -636,9 +636,9 @@ if ($page == 'domains' || $page == 'overview') {
]);
}
} elseif ($action == 'duplicate') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Domains::getLocal($userinfo, Request::postAll())->duplicate();
Domains::getLocal($userinfo, $_POST)->duplicate();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -55,7 +55,7 @@ if ($action == 'logout') {
$result = $result['switched_user'];
session_regenerate_id(true);
CurrentUser::setData($result);
$target = Request::get('target', 'index');
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
$redirect = "admin_" . $target . ".php";
if (!file_exists(\Froxlor\Froxlor::getInstallDir() . "/" . $redirect)) {
$redirect = "admin_index.php";
@@ -111,7 +111,7 @@ if ($page == 'overview') {
$overview['number_domains'] = $number_domains['number_domains'];
if (Request::get('lookfornewversion') == 'yes' || (isset($lookfornewversion) && $lookfornewversion == 'yes')) {
if ((isset($_GET['lookfornewversion']) && $_GET['lookfornewversion'] == 'yes') || (isset($lookfornewversion) && $lookfornewversion == 'yes')) {
try {
$json_result = Froxlor::getLocal($userinfo)->checkUpdate();
} catch (Exception $e) {
@@ -201,16 +201,16 @@ if ($page == 'overview') {
$languages = Language::getLanguages();
if (!empty($_POST)) {
if (Request::post('send') == 'changepassword') {
$old_password = Validate::validate(Request::post('old_password'), 'old password');
if ($_POST['send'] == 'changepassword') {
$old_password = Validate::validate($_POST['old_password'], 'old password');
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_ADMINS, 'adminid')) {
Response::standardError('oldpasswordnotcorrect');
}
try {
$new_password = Crypt::validatePassword(Request::post('new_password'), 'new password');
$new_password_confirm = Crypt::validatePassword(Request::post('new_password_confirm'), 'new password confirm');
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -244,9 +244,9 @@ if ($page == 'overview') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'changed password');
Response::redirectTo($filename);
}
} elseif (Request::post('send') == 'changetheme') {
} elseif ($_POST['send'] == 'changetheme') {
if (Settings::Get('panel.allow_theme_change_admin') == 1) {
$theme = Validate::validate(Request::post('theme'), 'theme');
$theme = Validate::validate($_POST['theme'], 'theme');
try {
Admins::getLocal($userinfo, [
'id' => $userinfo['adminid'],
@@ -259,8 +259,8 @@ if ($page == 'overview') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "changed his/her theme to '" . $theme . "'");
}
Response::redirectTo($filename);
} elseif (Request::post('send') == 'changelanguage') {
$def_language = Validate::validate(Request::post('def_language'), 'default language');
} elseif ($_POST['send'] == 'changelanguage') {
$def_language = Validate::validate($_POST['def_language'], 'default language');
if (isset($languages[$def_language])) {
try {

View File

@@ -70,7 +70,7 @@ if (($page == 'ipsandports' || $page == 'overview') && $userinfo['change_servers
$result = json_decode($json_result, true)['data'];
if (isset($result['id']) && $result['id'] == $id) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
IpsAndPorts::getLocal($userinfo, [
'id' => $id
@@ -91,9 +91,9 @@ if (($page == 'ipsandports' || $page == 'overview') && $userinfo['change_servers
}
}
} elseif ($action == 'add') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
IpsAndPorts::getLocal($userinfo, Request::postAll())->add();
IpsAndPorts::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -119,9 +119,9 @@ if (($page == 'ipsandports' || $page == 'overview') && $userinfo['change_servers
$result = json_decode($json_result, true)['data'];
if ($result['ip'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
IpsAndPorts::getLocal($userinfo, Request::postAll())->update();
IpsAndPorts::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -141,7 +141,7 @@ if (($page == 'ipsandports' || $page == 'overview') && $userinfo['change_servers
}
}
} elseif ($action == 'jqCheckIP') {
$ip = Request::post('ip', '');
$ip = $_POST['ip'] ?? "";
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
echo json_encode('<div id="ipnote" class="invalid-feedback">'.lng('error.invalidip', [$ip]).'</div>');
} elseif (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_NO_PRIV_RANGE)) {

View File

@@ -31,7 +31,6 @@ use Froxlor\UI\Collection;
use Froxlor\UI\HTML;
use Froxlor\UI\Listing;
use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response;
if ($page == 'log' && $userinfo['change_serversettings'] == '1') {
@@ -56,7 +55,7 @@ if ($page == 'log' && $userinfo['change_serversettings'] == '1') {
]
]);
} elseif ($action == 'truncate') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
SysLog::getLocal($userinfo, [
'min_to_keep' => 10

View File

@@ -42,11 +42,11 @@ if ($page == 'message') {
if ($action == '') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'viewed panel_message');
if (Request::post('send') == 'send') {
if (Request::post('recipient', -1) == 0 && $userinfo['customers_see_all'] == '1') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
if ($_POST['recipient'] == 0 && $userinfo['customers_see_all'] == '1') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'sending messages to admins');
$result = Database::query('SELECT `name`, `email` FROM `' . TABLE_PANEL_ADMINS . "`");
} elseif (Request::post('recipient', -1) == 1) {
} elseif ($_POST['recipient'] == 1) {
if ($userinfo['customers_see_all'] == '1') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, 'sending messages to ALL customers');
$result = Database::query('SELECT `firstname`, `name`, `company`, `email` FROM `' . TABLE_PANEL_CUSTOMERS . "`");
@@ -63,8 +63,8 @@ if ($page == 'message') {
Response::standardError('norecipientsgiven');
}
$subject = Request::post('subject');
$message = wordwrap(Request::post('message'), 70);
$subject = $_POST['subject'];
$message = wordwrap($_POST['message'], 70);
if (!empty($message)) {
$mailcounter = 0;
@@ -107,14 +107,14 @@ if ($page == 'message') {
}
}
} elseif ($action == 'showsuccess') {
$sentitems = Request::get('sentitems', 0);
$sentitems = isset($_GET['sentitems']) ? (int)$_GET['sentitems'] : 0;
if ($sentitems == 0) {
$note_type = 'info';
$note_msg = lng('message.norecipients');
} else {
$note_type = 'success';
$note_msg = lng('message.success', [$sentitems]);
$note_msg = str_replace('%s', $sentitems, lng('message.success'));
}
}
@@ -128,7 +128,7 @@ if ($page == 'message') {
$messages_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/messages/formfield.messages_add.php';
UI::view('user/form-note.html.twig', [
'formaction' => $linker->getLink(['section' => 'message', 'action' => '']),
'formaction' => $linker->getLink(['section' => 'message']),
'formdata' => $messages_add_data['messages_add'],
'actions_links' => [
[

View File

@@ -70,7 +70,7 @@ if (($page == 'mysqlserver' || $page == 'overview') && $userinfo['change_servers
$result = json_decode($json_result, true)['data'];
if (isset($result['id']) && $result['id'] == $id) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
MysqlServer::getLocal($userinfo, [
'id' => $id
@@ -91,9 +91,9 @@ if (($page == 'mysqlserver' || $page == 'overview') && $userinfo['change_servers
}
}
} elseif ($action == 'add') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
MysqlServer::getLocal($userinfo, Request::postAll())->add();
MysqlServer::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -119,9 +119,9 @@ if (($page == 'mysqlserver' || $page == 'overview') && $userinfo['change_servers
$result = json_decode($json_result, true)['data'];
if (isset($result['id']) && $result['id'] == $id) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
MysqlServer::getLocal($userinfo, Request::postAll())->update();
MysqlServer::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -35,11 +35,10 @@ require __DIR__ . '/lib/init.php';
use Froxlor\FroxlorLogger;
use Froxlor\UI\HTML;
use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response;
if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') {
if ($_POST['send'] == 'send') {
opcache_reset();
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "reset OPcache");
header('Location: ' . $linker->getLink([

View File

@@ -62,9 +62,9 @@ if ($page == 'overview') {
if ($action == 'add') {
if ((int)$userinfo['change_serversettings'] == 1) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
PhpSettings::getLocal($userinfo, Request::postAll())->add();
PhpSettings::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -114,7 +114,7 @@ if ($page == 'overview') {
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1 && $id != 1) // cannot delete the default php.config
{
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
PhpSettings::getLocal($userinfo, [
'id' => $id
@@ -148,9 +148,9 @@ if ($page == 'overview') {
$result = json_decode($json_result, true)['data'];
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
PhpSettings::getLocal($userinfo, Request::postAll())->update();
PhpSettings::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -200,9 +200,9 @@ if ($page == 'overview') {
if ($action == 'add') {
if ((int)$userinfo['change_serversettings'] == 1) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
FpmDaemons::getLocal($userinfo, Request::postAll())->add();
FpmDaemons::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -239,9 +239,9 @@ if ($page == 'overview') {
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1 && $id != 1) // cannot delete the default php.config
{
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
FpmDaemons::getLocal($userinfo, Request::postAll())->delete();
FpmDaemons::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -271,9 +271,9 @@ if ($page == 'overview') {
$result = json_decode($json_result, true)['data'];
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['change_serversettings'] == 1) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
FpmDaemons::getLocal($userinfo, Request::postAll())->update();
FpmDaemons::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -73,7 +73,7 @@ if ($page == '' || $page == 'overview') {
$result = json_decode($json_result, true)['data'];
if ($result['id'] != 0 && $result['id'] == $id && (int)$userinfo['adminid'] == $result['adminid']) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
HostingPlans::getLocal($userinfo, [
'id' => $id
@@ -96,9 +96,9 @@ if ($page == '' || $page == 'overview') {
Response::standardError('nopermissionsorinvalidid');
}
} elseif ($action == 'add') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
HostingPlans::getLocal($userinfo, Request::postAll())->add();
HostingPlans::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -176,9 +176,9 @@ if ($page == '' || $page == 'overview') {
}
$result['allowed_phpconfigs'] = json_encode($result['allowed_phpconfigs']);
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
HostingPlans::getLocal($userinfo, Request::postAll())->update();
HostingPlans::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -47,10 +47,10 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
$settings_data = PhpHelper::loadConfigArrayDir('./actions/admin/settings/');
Settings::loadSettingsInto($settings_data);
if (Request::post('send') == 'send') {
$_part = Request::get('part', '');
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$_part = isset($_GET['part']) ? $_GET['part'] : '';
if ($_part == '') {
$_part = Request::post('part', '');
$_part = isset($_POST['part']) ? $_POST['part'] : '';
}
if ($_part != '') {
@@ -69,12 +69,12 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
}
// check if the session timeout is too low #815
if (!empty(Request::post('session_sessiontimeout')) && intval(Request::post('session_sessiontimeout', 0)) < 60) {
if (isset($_POST['session_sessiontimeout']) && $_POST['session_sessiontimeout'] < 60) {
Response::standardError(['session_timeout', 'session_timeout_desc']);
}
try {
if (Form::processForm($settings_data, Request::postAll(), [
if (Form::processForm($settings_data, $_POST, [
'filename' => $filename,
'action' => $action,
'page' => $page,
@@ -97,9 +97,9 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
Response::dynamicError($e->getMessage(), $e->getCode());
}
} else {
$_part = Request::get('part', '');
$_part = isset($_GET['part']) ? $_GET['part'] : '';
if ($_part == '') {
$_part = Request::post('part', '');
$_part = isset($_POST['part']) ? $_POST['part'] : '';
}
$fields = Form::buildForm($settings_data, $_part);
@@ -140,7 +140,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
'phpinfo' => $phpinfo
]);
} elseif ($page == 'rebuildconfigs' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "rebuild configfiles");
Cronjob::inserttask(TaskId::REBUILD_VHOST);
Cronjob::inserttask(TaskId::CREATE_QUOTA);
@@ -158,7 +158,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
]);
}
} elseif ($page == 'updatecounters' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "updated resource-counters");
$updatecounters = User::updateCounters(true);
UI::view('user/resource-counter.html.twig', [
@@ -170,7 +170,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
]);
}
} elseif ($page == 'wipecleartextmailpws' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "wiped all cleartext mail passwords");
Database::query("UPDATE `" . TABLE_MAIL_USERS . "` SET `password` = '';");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = '0' WHERE `settinggroup` = 'system' AND `varname` = 'mailpwcleartext'");
@@ -181,7 +181,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
]);
}
} elseif ($page == 'wipequotas' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "wiped all mailquotas");
// Set the quota to 0 which means unlimited
@@ -194,7 +194,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
]);
}
} elseif ($page == 'enforcequotas' && $userinfo['change_serversettings'] == '1') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
// Fetch all accounts
$result_stmt = Database::query("SELECT `quota`, `customerid` FROM `" . TABLE_MAIL_USERS . "`");
@@ -233,9 +233,9 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
}
} elseif ($page == 'integritycheck' && $userinfo['change_serversettings'] == '1') {
$integrity = new IntegrityCheck();
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$integrity->fixAll();
} elseif (Request::get('action') == "fix") {
} elseif (isset($_GET['action']) && $_GET['action'] == "fix") {
HTML::askYesNo('admin_integritycheck_reallyfix', $filename, [
'page' => $page
]);
@@ -273,7 +273,7 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
Response::standardError('jsonextensionnotfound');
}
if (Request::get('action') == "export") {
if (isset($_GET['action']) && $_GET['action'] == "export") {
// export
try {
$json_result = Froxlor::getLocal($userinfo)->exportSettings();
@@ -285,9 +285,9 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
header('Content-type: application/json');
echo $json_export;
exit();
} elseif (Request::get('action') == "import") {
} elseif (isset($_GET['action']) && $_GET['action'] == "import") {
// import
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
// get uploaded file
if (isset($_FILES["import_file"]["tmp_name"])) {
$imp_content = file_get_contents($_FILES["import_file"]["tmp_name"]);
@@ -330,8 +330,8 @@ if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
$note_type = 'info';
$note_msg = lng('admin.smtptestnote');
if (Request::post('send') == 'send') {
$test_addr = Request::post('test_addr');
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$test_addr = isset($_POST['test_addr']) ? $_POST['test_addr'] : null;
// Initialize the mailingsystem
$testmail = new PHPMailer(true);

View File

@@ -192,7 +192,7 @@ if ($action == '') {
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
if ($result['varname'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_TEMPLATES . "`
WHERE `adminid` = :adminid
@@ -228,7 +228,7 @@ if ($action == '') {
if (Database::num_rows() > 0) {
$row = $result_stmt->fetch(PDO::FETCH_ASSOC);
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_TEMPLATES . "`
WHERE `adminid` = :adminid AND `id` = :id");
@@ -251,13 +251,13 @@ if ($action == '') {
Response::standardError('templatenotfound');
}
} elseif ($action == 'add') {
if (Request::post('prepare') == 'prepare') {
if (isset($_POST['prepare']) && $_POST['prepare'] == 'prepare') {
// email templates
$language = htmlentities(Validate::validate(Request::post('language'), 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
if (!array_key_exists($language, $languages)) {
Response::standardError('templatelanguageinvalid');
}
$template = Validate::validate(Request::post('template'), 'template');
$template = Validate::validate($_POST['template'], 'template');
$result_stmt = Database::prepare("
SELECT COUNT(*) as def FROM `" . TABLE_PANEL_TEMPLATES . "`
@@ -289,15 +289,15 @@ if ($action == '') {
'formdata' => $template_add_data['template_add'],
'replacers' => $template_add_data['template_replacers']
]);
} elseif (Request::post('send') == 'send' && empty(Request::post('filesend'))) {
} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && !isset($_POST['filesend'])) {
// email templates
$language = htmlentities(Validate::validate(Request::post('language'), 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
$language = htmlentities(Validate::validate($_POST['language'], 'language', '/^[^\r\n\0"\']+$/', 'nolanguageselect'));
if (!array_key_exists($language, $languages)) {
Response::standardError('templatelanguageinvalid');
}
$template = Validate::validate(Request::post('template'), 'template');
$subject = Validate::validate(Request::post('subject'), 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
$mailbody = Validate::validate(Request::post('mailbody'), 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
$template = Validate::validate($_POST['template'], 'template');
$subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
$mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
$templates = [];
$result_stmt = Database::prepare("
SELECT `varname` FROM `" . TABLE_PANEL_TEMPLATES . "`
@@ -347,10 +347,10 @@ if ($action == '') {
'page' => $page
]);
}
} elseif (Request::post('filesend') == 'filesend') {
} elseif (isset($_POST['filesend']) && $_POST['filesend'] == 'filesend') {
// file templates
$template = Validate::validate(Request::post('template'), 'template');
$filecontent = Validate::validate(Request::post('filecontent'), 'filecontent', '/^[^\0]+$/', 'filecontentnotset');
$template = Validate::validate($_POST['template'], 'template');
$filecontent = Validate::validate($_POST['filecontent'], 'filecontent', '/^[^\0]+$/', 'filecontentnotset');
$ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_PANEL_TEMPLATES . "` SET
@@ -371,7 +371,7 @@ if ($action == '') {
Response::redirectTo($filename, [
'page' => $page
]);
} elseif (empty(Request::get('files'))) {
} elseif (!isset($_GET['files'])) {
// email templates
$add = false;
$language_options = [];
@@ -483,9 +483,9 @@ if ($action == '') {
$result = $result_stmt->fetch(PDO::FETCH_ASSOC);
if ($result['varname'] != '') {
if (Request::post('send') == 'send') {
$subject = Validate::validate(Request::post('subject'), 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
$mailbody = Validate::validate(Request::post('mailbody'), 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$subject = Validate::validate($_POST['subject'], 'subject', '/^[^\r\n\0]+$/', 'nosubjectcreate');
$mailbody = Validate::validate($_POST['mailbody'], 'mailbody', '/^[^\0]+$/', 'nomailbodycreate');
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET
@@ -551,8 +551,8 @@ if ($action == '') {
$row = $result_stmt->fetch(PDO::FETCH_ASSOC);
// filetemplates
if (Request::post('filesend') == 'filesend') {
$filecontent = Validate::validate(Request::post('filecontent'), 'filecontent', '/^[^\0]+$/', 'filecontentnotset');
if (isset($_POST['filesend']) && $_POST['filesend'] == 'filesend') {
$filecontent = Validate::validate($_POST['filecontent'], 'filecontent', '/^[^\0]+$/', 'filecontentnotset');
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_TEMPLATES . "` SET
`value` = :value

View File

@@ -34,7 +34,6 @@ use Froxlor\Install\Update;
use Froxlor\Settings;
use Froxlor\System\Cronjob;
use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response;
use Froxlor\User;
@@ -49,8 +48,8 @@ if ($page == 'overview') {
$successful_update = false;
$message = '';
if (Request::post('send') == 'send') {
if ((!empty(Request::post('update_preconfig')) && intval(Request::post('update_changesagreed', 0)) != 0) || empty(Request::post('update_preconfig'))) {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
if ((isset($_POST['update_preconfig']) && isset($_POST['update_changesagreed']) && intval($_POST['update_changesagreed']) != 0) || !isset($_POST['update_preconfig'])) {
include_once Froxlor::getInstallDir() . 'install/updatesql.php';
User::updateCounters();

View File

@@ -61,7 +61,7 @@ if ($action == 'delete' && $id > 0) {
'section' => 'index',
'page' => $page
]);
} elseif (Request::post('send') == 'send' && $action == 'deletesure' && $id > 0) {
} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && $action == 'deletesure' && $id > 0) {
$chk = (AREA == 'admin' && $userinfo['customers_see_all'] == '1') ? true : false;
if (AREA == 'customer') {
$chk_stmt = Database::prepare("
@@ -94,7 +94,7 @@ if ($action == 'delete' && $id > 0) {
]);
}
} elseif ($action == 'add') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_API_KEYS . "` SET
`apikey` = :key, `secret` = :secret, `adminid` = :aid, `customerid` = :cid, `valid_until` = '-1', `allowed_from` = ''

641
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@
const AREA = 'customer';
require __DIR__ . '/lib/init.php';
use Froxlor\Api\Commands\SubDomains;
use Froxlor\Api\Commands\SubDomains as SubDomains;
use Froxlor\CurrentUser;
use Froxlor\Database\Database;
use Froxlor\Domain\Domain;
@@ -72,7 +72,7 @@ if ($page == 'overview' || $page == 'domains') {
}
$actions_links[] = [
'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/domains/',
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/domains/',
'target' => '_blank',
'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary'
@@ -106,9 +106,9 @@ if ($page == 'overview' || $page == 'domains') {
]);
if (isset($result['parentdomainid']) && $result['parentdomainid'] != '0' && $alias_check['count'] == 0) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
SubDomains::getLocal($userinfo, Request::postAll())->delete();
SubDomains::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -127,9 +127,9 @@ if ($page == 'overview' || $page == 'domains') {
}
} elseif ($action == 'add') {
if ($userinfo['subdomains_used'] < $userinfo['subdomains'] || $userinfo['subdomains'] == '-1') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
SubDomains::getLocal($userinfo, Request::postAll())->add();
SubDomains::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -248,9 +248,9 @@ if ($page == 'overview' || $page == 'domains') {
Response::standardError('domaincannotbeedited', $result['domain']);
}
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
SubDomains::getLocal($userinfo, Request::postAll())->update();
SubDomains::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -395,8 +395,8 @@ if ($page == 'overview' || $page == 'domains') {
Response::standardError('domains_canteditdomain');
}
} elseif ($action == 'jqSpeciallogfileNote') {
$domainid = intval(Request::post('id'));
$newval = intval(Request::post('newval'));
$domainid = intval($_POST['id']);
$newval = intval($_POST['newval']);
try {
$json_result = SubDomains::getLocal($userinfo, [
'id' => $domainid

View File

@@ -30,7 +30,6 @@ use Froxlor\Api\Commands\EmailAccounts;
use Froxlor\Api\Commands\EmailDomains;
use Froxlor\Api\Commands\EmailForwarders;
use Froxlor\Api\Commands\Emails;
use Froxlor\Cron\Mail\Rspamd;
use Froxlor\CurrentUser;
use Froxlor\Database\Database;
use Froxlor\FroxlorLogger;
@@ -77,7 +76,7 @@ if ($page == 'overview' || $page == 'emails') {
}
$actions_links[] = [
'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/emails/',
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/emails/',
'target' => '_blank',
'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary'
@@ -139,7 +138,7 @@ if ($page == 'email_domain') {
];
}
$actions_links[] = [
'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/emails/',
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/emails/',
'target' => '_blank',
'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary'
@@ -161,11 +160,11 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data'];
if (isset($result['email']) && $result['email'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Emails::getLocal($userinfo, [
'id' => $id,
'delete_userfiles' => Request::post('delete_userfiles', 0)
'delete_userfiles' => ($_POST['delete_userfiles'] ?? 0)
])->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
@@ -188,9 +187,9 @@ if ($page == 'email_domain') {
}
} elseif ($action == 'add') {
if ($userinfo['emails_used'] < $userinfo['emails'] || $userinfo['emails'] == '-1') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
$json_result = Emails::getLocal($userinfo, Request::postAll())->add();
$json_result = Emails::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -245,12 +244,7 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data'];
if (isset($result['email']) && $result['email'] != '') {
if (Request::post('send') == 'send') {
try {
Emails::getLocal($userinfo, Request::postAll())->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
if (isset($_POST['send']) && $_POST['send'] == 'send') {
Response::redirectTo($filename, [
'page' => $page
]);
@@ -287,12 +281,40 @@ if ($page == 'email_domain') {
$email_edit_data = include_once dirname(__FILE__) . '/lib/formfields/customer/email/formfield.emails_edit.php';
if (Settings::Get('catchall.catchall_enabled') != '1') {
unset($email_edit_data['emails_edit']['sections']['section_a']['fields']['mail_catchall']);
}
UI::view('user/form.html.twig', [
'formaction' => $linker->getLink(['section' => 'email']),
'formdata' => $email_edit_data['emails_edit'],
'editid' => $id
]);
}
} elseif ($action == 'togglecatchall' && $id != 0) {
try {
$json_result = Emails::getLocal($userinfo, [
'id' => $id
])->get();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
$result = json_decode($json_result, true)['data'];
try {
Emails::getLocal($userinfo, [
'id' => $id,
'iscatchall' => ($result['iscatchall'] == '1' ? 0 : 1)
])->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
Response::redirectTo($filename, [
'page' => $page,
'domainid' => $email_domainid,
'action' => 'edit',
'id' => $id,
]);
}
} elseif ($page == 'accounts') {
$email_domainid = Request::any('domainid', 0);
@@ -307,9 +329,9 @@ if ($page == 'email_domain') {
}
$result = json_decode($json_result, true)['data'];
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
EmailAccounts::getLocal($userinfo, Request::postAll())->add();
EmailAccounts::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -378,9 +400,9 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data'];
if (isset($result['popaccountid']) && $result['popaccountid'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
EmailAccounts::getLocal($userinfo, Request::postAll())->update();
EmailAccounts::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -437,9 +459,9 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data'];
if (isset($result['popaccountid']) && $result['popaccountid'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
EmailAccounts::getLocal($userinfo, Request::postAll())->update();
EmailAccounts::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -496,9 +518,9 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data'];
if (isset($result['popaccountid']) && $result['popaccountid'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
EmailAccounts::getLocal($userinfo, Request::postAll())->delete();
EmailAccounts::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -532,9 +554,9 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data'];
if (isset($result['email']) && $result['email'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
EmailForwarders::getLocal($userinfo, Request::postAll())->add();
EmailForwarders::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -594,15 +616,22 @@ if ($page == 'email_domain') {
$result = json_decode($json_result, true)['data'];
if (isset($result['destination']) && $result['destination'] != '') {
$forwarderid = Request::any('forwarderid', 0);
if (isset($_POST['forwarderid'])) {
$forwarderid = intval($_POST['forwarderid']);
} elseif (isset($_GET['forwarderid'])) {
$forwarderid = intval($_GET['forwarderid']);
} else {
$forwarderid = 0;
}
$result['destination'] = explode(' ', $result['destination']);
if (isset($result['destination'][$forwarderid]) && $result['email'] != $result['destination'][$forwarderid]) {
$forwarder = $result['destination'][$forwarderid];
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
EmailForwarders::getLocal($userinfo, Request::postAll())->delete();
EmailForwarders::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -75,7 +75,7 @@ if ($page == 'overview' || $page == 'htpasswds') {
];
$actions_links[] = [
'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/extras/',
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/',
'target' => '_blank',
'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary'
@@ -97,9 +97,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
$result = json_decode($json_result, true)['data'];
if (isset($result['username']) && $result['username'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
DirProtections::getLocal($userinfo, Request::postAll())->delete();
DirProtections::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -119,9 +119,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
}
}
} elseif ($action == 'add') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
DirProtections::getLocal($userinfo, Request::postAll())->add();
DirProtections::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -149,9 +149,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
$result = json_decode($json_result, true)['data'];
if (isset($result['username']) && $result['username'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
DirProtections::getLocal($userinfo, Request::postAll())->update();
DirProtections::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -200,7 +200,7 @@ if ($page == 'overview' || $page == 'htpasswds') {
];
$actions_links[] = [
'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/extras/',
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/',
'target' => '_blank',
'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary'
@@ -222,9 +222,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
$result = json_decode($json_result, true)['data'];
if (isset($result['customerid']) && $result['customerid'] != '' && $result['customerid'] == $userinfo['customerid']) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
DirOptions::getLocal($userinfo, Request::postAll())->delete();
DirOptions::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -240,9 +240,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
}
}
} elseif ($action == 'add') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
DirOptions::getLocal($userinfo, Request::postAll())->add();
DirOptions::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -271,9 +271,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
$result = json_decode($json_result, true)['data'];
if ((isset($result['customerid'])) && ($result['customerid'] != '') && ($result['customerid'] == $userinfo['customerid'])) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
DirOptions::getLocal($userinfo, Request::postAll())->update();
DirOptions::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -306,10 +306,10 @@ if ($page == 'overview' || $page == 'htpasswds') {
if (Settings::Get('system.exportenabled') == 1) {
if ($action == 'abort') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::export - aborted scheduled data export job");
try {
DataDump::getLocal($userinfo, Request::postAll())->delete();
DataDump::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -336,9 +336,9 @@ if ($page == 'overview' || $page == 'htpasswds') {
Response::dynamicError($e->getMessage());
}
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
DataDump::getLocal($userinfo, Request::postAll())->add();
DataDump::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -349,7 +349,7 @@ if ($page == 'overview' || $page == 'htpasswds') {
$actions_links = [
[
'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/extras/',
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/extras/',
'target' => '_blank',
'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary'

View File

@@ -65,7 +65,7 @@ if ($page == 'overview' || $page == 'accounts') {
];
}
$actions_links[] = [
'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/ftp-accounts/',
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/ftp-accounts/',
'target' => '_blank',
'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary'
@@ -87,9 +87,9 @@ if ($page == 'overview' || $page == 'accounts') {
$result = json_decode($json_result, true)['data'];
if (isset($result['username']) && $result['username'] != $userinfo['loginname']) {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Ftps::getLocal($userinfo, Request::postAll())->delete();
Ftps::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -108,9 +108,9 @@ if ($page == 'overview' || $page == 'accounts') {
}
} elseif ($action == 'add') {
if ($userinfo['ftps_used'] < $userinfo['ftps'] || $userinfo['ftps'] == '-1') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Ftps::getLocal($userinfo, Request::postAll())->add();
Ftps::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -164,9 +164,9 @@ if ($page == 'overview' || $page == 'accounts') {
$result = json_decode($json_result, true)['data'];
if (isset($result['username']) && $result['username'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Ftps::getLocal($userinfo, Request::postAll())->update();
Ftps::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}

View File

@@ -30,7 +30,6 @@ use Froxlor\Api\Commands\Customers as Customers;
use Froxlor\Cron\TaskId;
use Froxlor\CurrentUser;
use Froxlor\Database\Database;
use Froxlor\Database\DbManager;
use Froxlor\Froxlor;
use Froxlor\FroxlorLogger;
use Froxlor\Language;
@@ -38,7 +37,6 @@ use Froxlor\Settings;
use Froxlor\System\Cronjob;
use Froxlor\System\Crypt;
use Froxlor\UI\Panel\UI;
use Froxlor\UI\Request;
use Froxlor\UI\Response;
use Froxlor\Validate\Validate;
@@ -56,7 +54,7 @@ if ($action == 'logout') {
$result = $result['switched_user'];
session_regenerate_id(true);
CurrentUser::setData($result);
$target = Request::get('target', 'index');
$target = (isset($_GET['target']) ? $_GET['target'] : 'index');
$redirect = "admin_" . $target . ".php";
if (!file_exists(Froxlor::getInstallDir() . "/" . $redirect)) {
$redirect = "admin_index.php";
@@ -142,16 +140,16 @@ if ($page == 'overview') {
$languages = Language::getLanguages();
if (!empty($_POST)) {
if (Request::post('send') == 'changepassword') {
$old_password = Validate::validate(Request::post('old_password'), 'old password');
if ($_POST['send'] == 'changepassword') {
$old_password = Validate::validate($_POST['old_password'], 'old password');
if (!Crypt::validatePasswordLogin($userinfo, $old_password, TABLE_PANEL_CUSTOMERS, 'customerid')) {
Response::standardError('oldpasswordnotcorrect');
}
try {
$new_password = Crypt::validatePassword(Request::post('new_password'), 'new password');
$new_password_confirm = Crypt::validatePassword(Request::post('new_password_confirm'), 'new password confirm');
$new_password = Crypt::validatePassword($_POST['new_password'], 'new password');
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], 'new password confirm');
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -186,7 +184,7 @@ if ($page == 'overview') {
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, 'changed password');
// Update ftp password
if (Request::post('change_main_ftp') == 'true') {
if (isset($_POST['change_main_ftp']) && $_POST['change_main_ftp'] == 'true') {
$cryptPassword = Crypt::makeCryptPassword($new_password);
$stmt = Database::prepare("UPDATE `" . TABLE_FTP_USERS . "`
SET `password` = :password
@@ -202,7 +200,7 @@ if ($page == 'overview') {
}
// Update statistics password
if (Request::post('change_stats') == 'true') {
if (isset($_POST['change_stats']) && $_POST['change_stats'] == 'true') {
$new_stats_password = Crypt::makeCryptPassword($new_password, true);
$stmt = Database::prepare("UPDATE `" . TABLE_PANEL_HTPASSWDS . "`
@@ -218,32 +216,11 @@ if ($page == 'overview') {
Cronjob::inserttask(TaskId::REBUILD_VHOST);
}
// Update global myqsl user password
if ($userinfo['mysqls'] != 0 && Request::post('change_global_mysql') == 'true') {
$allowed_mysqlservers = json_decode($userinfo['allowed_mysqlserver'] ?? '[]', true);
foreach ($allowed_mysqlservers as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($log);
// give permission to the user on every access-host we have
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
if ($dbm->getManager()->userExistsOnHost($userinfo['loginname'], $mysql_access_host)) {
$dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, true);
} else {
// create global mysql user if not exists
$dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, false, true);
}
}
$dbm->getManager()->flushPrivileges();
}
}
Response::redirectTo($filename);
}
} elseif (Request::post('send') == 'changetheme') {
} elseif ($_POST['send'] == 'changetheme') {
if (Settings::Get('panel.allow_theme_change_customer') == 1) {
$theme = Validate::validate(Request::post('theme'), 'theme');
$theme = Validate::validate($_POST['theme'], 'theme');
try {
Customers::getLocal($userinfo, [
'id' => $userinfo['customerid'],
@@ -256,8 +233,8 @@ if ($page == 'overview') {
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "changed default theme to '" . $theme . "'");
}
Response::redirectTo($filename);
} elseif (Request::post('send') == 'changelanguage') {
$def_language = Validate::validate(Request::post('def_language'), 'default language');
} elseif ($_POST['send'] == 'changelanguage') {
$def_language = Validate::validate($_POST['def_language'], 'default language');
if (isset($languages[$def_language])) {
try {
Customers::getLocal($userinfo, [

View File

@@ -30,10 +30,8 @@ use Froxlor\Api\Commands\Mysqls;
use Froxlor\Api\Commands\MysqlServer;
use Froxlor\CurrentUser;
use Froxlor\Database\Database;
use Froxlor\Database\DbManager;
use Froxlor\FroxlorLogger;
use Froxlor\Settings;
use Froxlor\System\Crypt;
use Froxlor\UI\Collection;
use Froxlor\UI\HTML;
use Froxlor\UI\Listing;
@@ -76,32 +74,17 @@ if ($page == 'overview' || $page == 'mysqls') {
];
}
$view = 'user/table.html.twig';
if ($collection->count() > 0) {
$view = 'user/table-note.html.twig';
$actions_links[] = [
'href' => $linker->getLink(['section' => 'mysql', 'page' => 'mysqls', 'action' => 'global_user']),
'label' => lng('mysql.edit_global_user'),
'icon' => 'fa-solid fa-user-tie',
'class' => 'btn-outline-secondary'
];
}
$actions_links[] = [
'href' => \Froxlor\Froxlor::getDocsUrl() . 'user-guide/databases/',
'href' => \Froxlor\Froxlor::DOCS_URL . 'user-guide/databases/',
'target' => '_blank',
'icon' => 'fa-solid fa-circle-info',
'class' => 'btn-outline-secondary'
];
UI::view($view, [
UI::view('user/table.html.twig', [
'listing' => Listing::format($collection, $mysql_list_data, 'mysql_list'),
'actions_links' => $actions_links,
'entity_info' => lng('mysql.description'),
// alert-box
'type' => 'info',
'alert_msg' => lng('mysql.globaluserinfo', [$userinfo['loginname']]),
'entity_info' => lng('mysql.description')
]);
} elseif ($action == 'delete' && $id != 0) {
try {
@@ -123,9 +106,9 @@ if ($page == 'overview' || $page == 'mysqls') {
$result['dbserver'] = 0;
}
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Mysqls::getLocal($userinfo, Request::postAll())->delete();
Mysqls::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -146,9 +129,9 @@ if ($page == 'overview' || $page == 'mysqls') {
}
} elseif ($action == 'add') {
if ($userinfo['mysqls_used'] < $userinfo['mysqls'] || $userinfo['mysqls'] == '-1') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
Mysqls::getLocal($userinfo, Request::postAll())->add();
Mysqls::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -186,9 +169,9 @@ if ($page == 'overview' || $page == 'mysqls') {
$result = json_decode($json_result, true)['data'];
if (isset($result['databasename']) && $result['databasename'] != '') {
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
$json_result = Mysqls::getLocal($userinfo, Request::postAll())->update();
$json_result = Mysqls::getLocal($userinfo, $_POST)->update();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@@ -216,45 +199,5 @@ if ($page == 'overview' || $page == 'mysqls') {
]);
}
}
} elseif ($action == 'global_user') {
$allowed_mysqlservers = json_decode($userinfo['allowed_mysqlserver'] ?? '[]', true);
if ($userinfo['mysqls'] == 0 || empty($allowed_mysqlservers)) {
Response::dynamicError('No permission');
}
if (Request::post('send') == 'send') {
$new_password = Crypt::validatePassword(Request::post('mysql_password'));
foreach ($allowed_mysqlservers as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($log);
// give permission to the user on every access-host we have
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
if ($dbm->getManager()->userExistsOnHost($userinfo['loginname'], $mysql_access_host)) {
// update password
$dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, true, true);
} else {
// create missing user
$dbm->getManager()->grantPrivilegesTo($userinfo['loginname'], $new_password, $mysql_access_host, false, false, true);
}
}
$dbm->getManager()->flushPrivileges();
}
Response::redirectTo($filename, [
'page' => 'overview'
]);
} else {
$mysql_global_user_data = include_once dirname(__FILE__) . '/lib/formfields/customer/mysql/formfield.mysql_global_user.php';
UI::view('user/form.html.twig', [
'formaction' => $linker->getLink(['section' => 'mysql', 'page' => 'mysqls', 'action' => 'global_user']),
'formdata' => $mysql_global_user_data['mysql_global_user'],
'editid' => $id
]);
}
}
}

View File

@@ -30,7 +30,6 @@ if (!defined('AREA')) {
use Froxlor\Api\Commands\DomainZones;
use Froxlor\Dns\Dns;
use Froxlor\Settings;
use Froxlor\UI\Collection;
use Froxlor\UI\HTML;
use Froxlor\UI\Listing;
@@ -43,11 +42,11 @@ use Froxlor\UI\Response;
$domain_id = (int)Request::any('domain_id');
$record = Request::post('dns_record');
$type = Request::post('dns_type', 'A');
$prio = Request::post('dns_mxp');
$content = Request::post('dns_content');
$ttl = (int)Request::post('dns_ttl', Settings::get('system.defaultttl'));
$record = isset($_POST['dns_record']) ? trim($_POST['dns_record']) : null;
$type = isset($_POST['dns_type']) ? $_POST['dns_type'] : 'A';
$prio = isset($_POST['dns_mxp']) ? (int)$_POST['dns_mxp'] : null;
$content = isset($_POST['dns_content']) ? trim($_POST['dns_content']) : null;
$ttl = isset($_POST['dns_ttl']) ? (int)$_POST['dns_ttl'] : 18000;
// get domain-name
$domain = Dns::getAllowedDomainEntry($domain_id, AREA, $userinfo);
@@ -72,7 +71,7 @@ if ($action == 'add_record' && !empty($_POST)) {
$errors = str_replace("\n", "<br>", $e->getMessage());
}
} elseif ($action == 'delete') {
$entry_id = (int)Request::get('id', 0);
$entry_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
HTML::askYesNo('dnsentry_reallydelete', $filename, [
'id' => $entry_id,
'domain_id' => $domain_id,
@@ -83,9 +82,9 @@ if ($action == 'add_record' && !empty($_POST)) {
'page' => $page,
'domain_id' => $domain_id
]);
} elseif (Request::post('send') == 'send' && $action == 'deletesure' && !empty($_POST)) {
$entry_id = (int)Request::post('id', 0);
$domain_id = (int)Request::post('domain_id', 0);
} elseif (isset($_POST['send']) && $_POST['send'] == 'send' && $action == 'deletesure' && !empty($_POST)) {
$entry_id = isset($_POST['id']) ? (int)$_POST['id'] : 0;
$domain_id = isset($_POST['domain_id']) ? (int)$_POST['domain_id'] : 0;
// remove entry
if ($entry_id > 0 && $domain_id > 0) {
try {

View File

@@ -77,7 +77,7 @@ if (!empty($errid)) {
$mail_html = nl2br($mail_body);
// send actual report to dev-team
if (Request::post('send') == 'send') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
// send mail and say thanks
$_mailerror = false;
try {

185
index.php
View File

@@ -54,7 +54,7 @@ if ($action == '2fa_entercode') {
Response::redirectTo('index.php');
exit();
}
$smessage = (int)Request::get('showmessage', 0);
$smessage = isset($_GET['showmessage']) ? (int)$_GET['showmessage'] : 0;
$message = "";
if ($smessage > 0) {
$message = lng('error.2fa_wrongcode');
@@ -62,7 +62,6 @@ if ($action == '2fa_entercode') {
// show template to enter code
UI::view('login/enter2fa.html.twig', [
'pagetitle' => lng('login.2fa'),
'remember_me' => (Settings::Get('panel.db_version') >= 202407200) ? true : false,
'message' => $message
]);
} elseif ($action == '2fa_verify') {
@@ -72,8 +71,7 @@ if ($action == '2fa_entercode') {
Response::redirectTo('index.php');
exit();
}
$code = Request::post('2fa_code');
$remember = Request::post('2fa_remember');
$code = isset($_POST['2fa_code']) ? $_POST['2fa_code'] : null;
// verify entered code
$tfa = new FroxlorTwoFactorAuth('Froxlor ' . Settings::Get('system.hostname'));
// get user-data
@@ -85,8 +83,7 @@ if ($action == '2fa_entercode') {
// verify code set to user's data_2fa field
$sel_stmt = Database::prepare("SELECT `data_2fa` FROM " . $table . " WHERE `" . $field . "` = :uid");
$userinfo_code = Database::pexecute_first($sel_stmt, ['uid' => $uid]);
// 60sec discrepancy (possible slow email delivery)
$result = $tfa->verifyCode($userinfo_code['data_2fa'], $code, 60);
$result = $tfa->verifyCode($userinfo_code['data_2fa'], $code);
} else {
$result = $tfa->verifyCode($_SESSION['secret_2fa'], $code, 3);
}
@@ -108,49 +105,20 @@ if ($action == '2fa_entercode') {
$userinfo['adminsession'] = $isadmin;
$userinfo['userid'] = $uid;
// when using email-2fa, remove the one-time-code
if ($userinfo['type_2fa'] == '1') {
$del_stmt = Database::prepare("UPDATE " . $table . " SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
Database::pexecute_first($del_stmt, [
'uid' => $uid
]);
}
// when remember is activated, set the cookie
if ($remember) {
$selector = base64_encode(Froxlor::genSessionId(9));
$authenticator = Froxlor::genSessionId(33);
$valid_until = time()+60*60*24*30;
$ins_stmt = Database::prepare("
INSERT INTO `".TABLE_PANEL_2FA_TOKENS."` SET
`selector` = :selector,
`token` = :authenticator,
`userid` = :userid,
`valid_until` = :valid_until
");
Database::pexecute($ins_stmt, [
'selector' => $selector,
'authenticator' => hash('sha256', $authenticator),
'userid' => $uid,
'valid_until' => $valid_until
]);
$cookie_params = [
'expires' => $valid_until, // 30 days
'path' => '/',
'domain' => UI::getCookieHost(),
'secure' => UI::requestIsHttps(),
'httponly' => true,
'samesite' => 'Strict'
];
setcookie('frx_2fa_remember', $selector.':'.base64_encode($authenticator), $cookie_params);
}
// if not successful somehow - start again
if (!finishLogin($userinfo)) {
Response::redirectTo('index.php', [
'showmessage' => '2'
]);
}
// when using email-2fa, remove the one-time-code
if ($userinfo['type_2fa'] == '1') {
$del_stmt = Database::prepare("UPDATE " . $table . " SET `data_2fa` = '' WHERE `" . $field . "` = :uid");
$userinfo = Database::pexecute_first($del_stmt, [
'uid' => $uid
]);
}
exit();
}
// wrong 2fa code - treat like "wrong password"
@@ -194,41 +162,30 @@ if ($action == '2fa_entercode') {
exit();
} elseif ($action == 'login') {
if (!empty($_POST)) {
$loginname = Validate::validate(Request::post('loginname'), 'loginname');
$password = Validate::validate(Request::post('password'), 'password');
$loginname = Validate::validate($_POST['loginname'], 'loginname');
$password = Validate::validate($_POST['password'], 'password');
$select_additional = '';
if (Settings::Get('panel.db_version') >= 202312230) {
$select_additional = ' AND `gui_access` = 1';
}
$stmt = Database::prepare("
SELECT `loginname` AS `customer`
FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `loginname`= :loginname" .
$select_additional
);
$stmt = Database::prepare("SELECT `loginname` AS `customer` FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `loginname`= :loginname");
Database::pexecute($stmt, [
"loginname" => $loginname
]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$is_admin = false;
$table = "";
if ($row && $row['customer'] == $loginname) {
$table = "`" . TABLE_PANEL_CUSTOMERS . "`";
$uid = 'customerid';
$adminsession = '0';
$is_admin = false;
} else {
$is_admin = true;
if ((int)Settings::Get('login.domain_login') == 1) {
$domainname = $idna_convert->encode(preg_replace([
'/\:(\d)+$/',
'/^https?\:\/\//'
], '', $loginname));
$stmt = Database::prepare("
SELECT `customerid`
FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `domain` = :domain
");
$stmt = Database::prepare("SELECT `customerid` FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `domain` = :domain");
Database::pexecute($stmt, [
"domain" => $domainname
]);
@@ -237,11 +194,8 @@ if ($action == '2fa_entercode') {
if (isset($row2['customerid']) && $row2['customerid'] > 0) {
$loginname = Customer::getCustomerDetail($row2['customerid'], 'loginname');
if ($loginname !== false) {
$stmt = Database::prepare("
SELECT `loginname` AS `customer`
FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `loginname`= :loginname
");
$stmt = Database::prepare("SELECT `loginname` AS `customer` FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `loginname`= :loginname");
Database::pexecute($stmt, [
"loginname" => $loginname
]);
@@ -250,17 +204,13 @@ if ($action == '2fa_entercode') {
$table = "`" . TABLE_PANEL_CUSTOMERS . "`";
$uid = 'customerid';
$adminsession = '0';
$is_admin = false;
}
}
}
}
}
if (empty($table)) {
// try login as admin of no customer-login method worked
$is_admin = true;
}
if ((Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) && $is_admin == false) {
Response::redirectTo('index.php');
exit();
@@ -268,11 +218,9 @@ if ($action == '2fa_entercode') {
if ($is_admin) {
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
$stmt = Database::prepare("
SELECT `loginname` AS `admin` FROM `" . TABLE_PANEL_ADMINS . "`
$stmt = Database::prepare("SELECT `loginname` AS `admin` FROM `" . TABLE_PANEL_ADMINS . "`
WHERE `loginname`= :loginname
AND `change_serversettings` = '1'
");
AND `change_serversettings` = '1'");
Database::pexecute($stmt, [
"loginname" => $loginname
]);
@@ -283,16 +231,8 @@ if ($action == '2fa_entercode') {
exit();
}
} else {
$select_additional = '';
if (Settings::Get('panel.db_version') >= 202312230) {
$select_additional = ' AND `gui_access` = 1';
}
$stmt = Database::prepare("
SELECT `loginname` AS `admin`
FROM `" . TABLE_PANEL_ADMINS . "`
WHERE `loginname`= :loginname" .
$select_additional
);
$stmt = Database::prepare("SELECT `loginname` AS `admin` FROM `" . TABLE_PANEL_ADMINS . "`
WHERE `loginname`= :loginname");
Database::pexecute($stmt, [
"loginname" => $loginname
]);
@@ -317,9 +257,8 @@ if ($action == '2fa_entercode') {
}
}
$userinfo_stmt = Database::prepare("
SELECT * FROM $table WHERE `loginname`= :loginname
");
$userinfo_stmt = Database::prepare("SELECT * FROM $table
WHERE `loginname`= :loginname");
Database::pexecute($userinfo_stmt, [
"loginname" => $loginname
]);
@@ -342,11 +281,9 @@ if ($action == '2fa_entercode') {
} else {
// login correct
// reset loginfail_counter, set lastlogin_succ
$stmt = Database::prepare("
UPDATE $table
SET `lastlogin_succ`= :lastlogin_succ, `loginfail_count`='0'
WHERE `$uid`= :uid
");
$stmt = Database::prepare("UPDATE $table
SET `lastlogin_succ`= :lastlogin_succ, `loginfail_count`='0'
WHERE `$uid`= :uid");
Database::pexecute($stmt, [
"lastlogin_succ" => time(),
"uid" => $userinfo[$uid]
@@ -356,11 +293,9 @@ if ($action == '2fa_entercode') {
}
} else {
// login incorrect
$stmt = Database::prepare("
UPDATE $table
$stmt = Database::prepare("UPDATE $table
SET `lastlogin_fail`= :lastlogin_fail, `loginfail_count`=`loginfail_count`+1
WHERE `$uid`= :uid
");
WHERE `$uid`= :uid");
Database::pexecute($stmt, [
"lastlogin_fail" => time(),
"uid" => $userinfo[$uid]
@@ -381,25 +316,6 @@ if ($action == '2fa_entercode') {
// 2FA activated
if (Settings::Get('2fa.enabled') == '1' && $userinfo['type_2fa'] > 0) {
// check for remember cookie
if (!empty($_COOKIE['frx_2fa_remember'])) {
list($selector, $authenticator) = explode(':', $_COOKIE['frx_2fa_remember']);
$sel_stmt = Database::prepare("SELECT `token` FROM `".TABLE_PANEL_2FA_TOKENS."` WHERE `selector` = :selector AND `userid` = :uid AND `valid_until` >= UNIX_TIMESTAMP()");
$token_check = Database::pexecute_first($sel_stmt, ['selector' => $selector, 'uid' => $userinfo[$uid]]);
if ($token_check && hash_equals($token_check['token'], hash('sha256', base64_decode($authenticator)))) {
if (!finishLogin($userinfo)) {
Response::redirectTo('index.php', [
'showmessage' => '2'
]);
}
exit();
}
// not found or invalid, this cookie is useless, get rid of it
unset($_COOKIE['frx_2fa_remember']);
setcookie('frx_2fa_remember', "", time()-3600);
}
// redirect to code-enter-page
$_SESSION['secret_2fa'] = ($userinfo['type_2fa'] == 2 ? $userinfo['data_2fa'] : 'email');
$_SESSION['uid_2fa'] = $userinfo[$uid];
@@ -467,7 +383,7 @@ if ($action == '2fa_entercode') {
}
exit();
} else {
$smessage = (int)Request::get('showmessage', 0);
$smessage = isset($_GET['showmessage']) ? (int)$_GET['showmessage'] : 0;
$message = '';
$successmessage = '';
@@ -504,20 +420,25 @@ if ($action == '2fa_entercode') {
}
// Pass the last used page if needed
$lastscript = Request::any('script', '');
if (!empty($lastscript)) {
$lastscript = "";
if (isset($_REQUEST['script']) && $_REQUEST['script'] != "") {
$lastscript = $_REQUEST['script'];
$lastscript = str_replace("..", "", $lastscript);
$lastscript = htmlspecialchars($lastscript, ENT_QUOTES);
if (file_exists(__DIR__ . "/" . $lastscript)) {
$_SESSION['lastscript'] = $lastscript;
} else {
if (!file_exists(__DIR__ . "/" . $lastscript)) {
$lastscript = "";
}
}
$lastqrystr = Request::any('qrystr', '');
$lastqrystr = "";
if (isset($_REQUEST['qrystr']) && $_REQUEST['qrystr'] != "") {
$lastqrystr = urlencode($_REQUEST['qrystr']);
}
if (!empty($lastscript)) {
$_SESSION['lastscript'] = $lastscript;
}
if (!empty($lastqrystr)) {
$lastqrystr = urlencode($lastqrystr);
$_SESSION['lastqrystr'] = $lastqrystr;
}
@@ -535,8 +456,8 @@ if ($action == 'forgotpwd') {
$message = '';
if (!empty($_POST)) {
$loginname = Validate::validate(Request::post('loginname'), 'loginname');
$email = Validate::validateEmail(Request::post('loginemail'));
$loginname = Validate::validate($_POST['loginname'], 'loginname');
$email = Validate::validateEmail($_POST['loginemail']);
$result_stmt = Database::prepare("SELECT `adminid`, `customerid`, `customernumber`, `firstname`, `name`, `company`, `email`, `loginname`, `def_language`, `deactivated` FROM `" . TABLE_PANEL_CUSTOMERS . "`
WHERE `loginname`= :loginname
AND `email`= :email");
@@ -733,9 +654,9 @@ if ($action == 'resetpwd') {
"oldest" => time() - 86400
]);
$activationcode = Request::get('resetcode');
if (!empty($activationcode) && strlen($activationcode) == 50) {
if (isset($_GET['resetcode']) && strlen($_GET['resetcode']) == 50) {
// Check if activation code is valid
$activationcode = $_GET['resetcode'];
$timestamp = substr($activationcode, 15, 10);
$third = substr($activationcode, 25, 15);
$check = substr($activationcode, 40, 10);
@@ -750,8 +671,8 @@ if ($action == 'resetpwd') {
if ($result !== false) {
try {
$new_password = Crypt::validatePassword(Request::post('new_password'), true);
$new_password_confirm = Crypt::validatePassword(Request::post('new_password_confirm'), true);
$new_password = Crypt::validatePassword($_POST['new_password'], true);
$new_password_confirm = Crypt::validatePassword($_POST['new_password_confirm'], true);
} catch (Exception $e) {
$message = $e->getMessage();
}
@@ -880,8 +801,8 @@ function finishLogin($userinfo)
$theme = $userinfo['theme'];
} else {
$theme = Settings::Get('panel.default_theme');
CurrentUser::setField('theme', $theme);
}
CurrentUser::setField('theme', $theme);
$qryparams = [];
if (!empty($_SESSION['lastqrystr'])) {

View File

@@ -94,11 +94,6 @@ CREATE TABLE `mail_virtual` (
`popaccountid` int(11) NOT NULL default '0',
`iscatchall` tinyint(1) unsigned NOT NULL default '0',
`description` varchar(255) NOT NULL DEFAULT '',
`spam_tag_level` float(4,1) NOT NULL DEFAULT 7.0,
`rewrite_subject` tinyint(1) NOT NULL default '1',
`spam_kill_level` float(4,1) NOT NULL DEFAULT 14.0,
`bypass_spam` tinyint(1) NOT NULL default '0',
`policy_greylist` tinyint(1) NOT NULL default '1',
PRIMARY KEY (`id`),
KEY `email` (`email`)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
@@ -160,7 +155,6 @@ CREATE TABLE `panel_admins` (
`type_2fa` tinyint(1) NOT NULL default '0',
`data_2fa` varchar(25) NOT NULL default '',
`api_allowed` tinyint(1) NOT NULL default '1',
`gui_access` tinyint(1) NOT NULL default '1',
PRIMARY KEY (`adminid`),
UNIQUE KEY `loginname` (`loginname`)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
@@ -229,7 +223,6 @@ CREATE TABLE `panel_customers` (
`api_allowed` tinyint(1) NOT NULL default '1',
`logviewenabled` tinyint(1) NOT NULL default '0',
`allowed_mysqlserver` text NOT NULL,
`gui_access` tinyint(1) NOT NULL default '1',
PRIMARY KEY (`customerid`),
UNIQUE KEY `loginname` (`loginname`)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
@@ -387,18 +380,22 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES
('logger', 'logfile', ''),
('logger', 'logtypes', 'syslog,mysql'),
('logger', 'severity', '1'),
('antispam', 'activated', '0'),
('antispam', 'config_file', '/etc/rspamd/local.d/froxlor_settings.conf'),
('antispam', 'reload_command', 'service rspamd restart'),
('antispam', 'dkim_keylength', '1024'),
('dkim', 'use_dkim', '0'),
('dkim', 'dkim_prefix', '/etc/postfix/dkim/'),
('dkim', 'dkim_domains', 'domains'),
('dkim', 'dkim_dkimkeys', 'dkim-keys.conf'),
('dkim', 'dkimrestart_command', 'service dkim-filter restart'),
('dkim', 'privkeysuffix', '.priv'),
('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'),
('dmarc', 'use_dmarc', '0'),
('dmarc', 'dmarc_entry', 'v=DMARC1; p=none;'),
('dkim', 'dkim_algorithm', 'all'),
('dkim', 'dkim_keylength', '1024'),
('dkim', 'dkim_servicetype', '0'),
('dkim', 'dkim_notes', ''),
('defaultwebsrverrhandler', 'enabled', '0'),
('defaultwebsrverrhandler', 'err401', ''),
('defaultwebsrverrhandler', 'err403', ''),
@@ -496,6 +493,7 @@ opcache.save_comments
opcache.use_cwd
opcache.fast_shutdown'),
('phpfpm', 'ini_admin_values', 'cgi.redirect_status_env
date.timezone
disable_classes
disable_functions
error_log
@@ -638,8 +636,6 @@ opcache.validate_timestamps'),
('system', 'available_shells', ''),
('system', 'le_froxlor_enabled', '0'),
('system', 'le_froxlor_redirect', '0'),
('system', 'le_renew_hook', 'systemctl restart postfix dovecot proftpd'),
('system', 'le_renew_services', ''),
('system', 'letsencryptacmeconf', '/etc/apache2/conf-enabled/acme.conf'),
('system', 'mail_use_smtp', '0'),
('system', 'mail_smtp_host', 'localhost'),
@@ -730,8 +726,8 @@ opcache.validate_timestamps'),
('panel', 'logo_overridecustom', '0'),
('panel', 'settings_mode', '0'),
('panel', 'menu_collapsed', '1'),
('panel', 'version', '2.2.2'),
('panel', 'db_version', '202409280');
('panel', 'version', '2.1.9'),
('panel', 'db_version', '202312120');
DROP TABLE IF EXISTS `panel_tasks`;
@@ -1049,15 +1045,4 @@ CREATE TABLE `panel_loginlinks` (
`allowed_from` text NOT NULL,
UNIQUE KEY `loginname` (`loginname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
DROP TABLE IF EXISTS `panel_2fa_tokens`;
CREATE TABLE `panel_2fa_tokens` (
`id` int(11) NOT NULL auto_increment,
`selector` varchar(200) NOT NULL,
`token` varchar(200) NOT NULL,
`userid` int(11) NOT NULL default '0',
`valid_until` int(15) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
FROXLORSQL;

View File

@@ -99,6 +99,7 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
}
Update::lastStepStatus(0);
Update::showUpdateStep("Cleaning up old files");
$to_clean = array(
"install/lib",
"install/lng",
@@ -120,7 +121,30 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
"lng/swedish.lng.php",
"scripts",
);
Update::cleanOldFiles($to_clean);
$disabled = explode(',', ini_get('disable_functions'));
$exec_allowed = !in_array('exec', $disabled);
$del_list = "";
foreach ($to_clean as $filedir) {
$complete_filedir = Froxlor::getInstallDir() . $filedir;
if (file_exists($complete_filedir)) {
if ($exec_allowed) {
FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir));
} else {
$del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL;
}
}
}
if ($exec_allowed) {
Update::lastStepStatus(0);
} else {
if (empty($del_list)) {
// none of the files existed
Update::lastStepStatus(0);
} else {
Update::lastStepStatus(1, 'manual commands needed',
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>');
}
}
Update::showUpdateStep("Adding new settings");
$panel_settings_mode = isset($_POST['panel_settings_mode']) ? (int)$_POST['panel_settings_mode'] : 0;

View File

@@ -149,6 +149,7 @@ if (Froxlor::isFroxlorVersion('2.1.0-rc2')) {
}
if (Froxlor::isDatabaseVersion('202311260')) {
Update::showUpdateStep("Cleaning up old files");
$to_clean = array(
"install/updates/froxlor/update_2.x.inc.php",
"install/updates/preconfig/preconfig_2.x.inc.php",
@@ -174,8 +175,33 @@ if (Froxlor::isDatabaseVersion('202311260')) {
"templates/Froxlor/user/change_theme.html.twig",
"tests/Backup/CustomerBackupsTest.php"
);
Update::cleanOldFiles($to_clean);
$disabled = explode(',', ini_get('disable_functions'));
$exec_allowed = !in_array('exec', $disabled);
$del_list = "";
foreach ($to_clean as $filedir) {
$complete_filedir = Froxlor::getInstallDir() . $filedir;
if (file_exists($complete_filedir)) {
if ($exec_allowed) {
FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir));
} else {
$del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL;
}
}
}
if ($exec_allowed) {
Update::lastStepStatus(0);
} else {
if (empty($del_list)) {
// none of the files existed
Update::lastStepStatus(0);
} else {
Update::lastStepStatus(
1,
'manual commands needed',
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>'
);
}
}
Froxlor::updateToDbVersion('202312050');
}
@@ -190,6 +216,7 @@ if (Froxlor::isFroxlorVersion('2.1.0')) {
}
if (Froxlor::isDatabaseVersion('202312050')) {
Update::showUpdateStep("Cleaning up old files");
$to_clean = array(
"lib/configfiles/centos7.xml",
"lib/configfiles/centos8.xml",
@@ -198,8 +225,33 @@ if (Froxlor::isDatabaseVersion('202312050')) {
"lib/configfiles/buster.xml",
"lib/configfiles/bionic.xml",
);
Update::cleanOldFiles($to_clean);
$disabled = explode(',', ini_get('disable_functions'));
$exec_allowed = !in_array('exec', $disabled);
$del_list = "";
foreach ($to_clean as $filedir) {
$complete_filedir = Froxlor::getInstallDir() . $filedir;
if (file_exists($complete_filedir)) {
if ($exec_allowed) {
FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir));
} else {
$del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL;
}
}
}
if ($exec_allowed) {
Update::lastStepStatus(0);
} else {
if (empty($del_list)) {
// none of the files existed
Update::lastStepStatus(0);
} else {
Update::lastStepStatus(
1,
'manual commands needed',
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>'
);
}
}
Froxlor::updateToDbVersion('202312100');
}

View File

@@ -1,185 +0,0 @@
<?php
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can also view it online at
* https://files.froxlor.org/misc/COPYING.txt
*
* @copyright the authors
* @author Froxlor team <team@froxlor.org>
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
use Froxlor\Database\Database;
use Froxlor\Froxlor;
use Froxlor\Install\Update;
use Froxlor\Settings;
if (!defined('_CRON_UPDATE')) {
if (!defined('AREA') || (defined('AREA') && AREA != 'admin') || !isset($userinfo['loginname']) || (isset($userinfo['loginname']) && $userinfo['loginname'] == '')) {
header('Location: ../../../../index.php');
exit();
}
}
if (Froxlor::isFroxlorVersion('2.1.9')) {
Update::showUpdateStep("Enhancing virtual email table");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `spam_tag_level` float(4,1) NOT NULL DEFAULT 7.0;");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `spam_kill_level` float(4,1) NOT NULL DEFAULT 14.0;");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `bypass_spam` tinyint(1) NOT NULL default '0';");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `policy_greylist` tinyint(1) NOT NULL default '1';");
Update::lastStepStatus(0);
Update::showUpdateStep("Adjusting settings");
$antispam_activated = $_POST['antispam_activated'] ?? 0;
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam', `varname` = 'activated', `value` = '" . (int)$antispam_activated . "' WHERE `settinggroup` = 'dkim' AND `varname` = 'use_dkim';");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam', `varname` = 'reload_command', `value` = 'service rspamd restart' WHERE `settinggroup` = 'dkim' AND `varname` = 'dkimrestart_command';");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam', `varname` = 'config_file', `value` = '/etc/rspamd/local.d/froxlor_settings.conf' WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_prefix';");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam' WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_keylength';");
Settings::AddNew("dmarc.use_dmarc", "0");
Settings::AddNew("dmarc.dmarc_entry", "v=DMARC1; p=none;");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'privkeysuffix';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_domains';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_algorithm';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_notes';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_add_adsp';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_dkimkeys';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_servicetype';");
Database::query("DELETE FROM `" . TABLE_PANEL_SETTINGS . "` WHERE `settinggroup` = 'dkim' AND `varname` = 'dkim_add_adsppolicy';");
Update::lastStepStatus(0);
if ($antispam_activated) {
Update::showUpdateStep("Converting existing domainkeys");
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `dkim` = '1' AND `dkim_pubkey` <> ''");
Database::pexecute($sel_stmt);
$upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `dkim_pubkey` = :pkey WHERE `id` = :did");
while ($domain = $sel_stmt->fetch(\PDO::FETCH_ASSOC)) {
$pubkey = trim(preg_replace(
'/-----BEGIN PUBLIC KEY-----(.+)-----END PUBLIC KEY-----/s',
'$1',
str_replace("\n", '', $domain['dkim_pubkey'])
));
Database::pexecute($upd_stmt, ['pkey' => $pubkey, 'did' => $domain['id']]);
}
Update::lastStepStatus(0);
Update::showUpdateStep("Configure antispam services");
$froxlorCliBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
$currentDistro = Settings::Get('system.distribution');
$manual_command = <<<EOC
{$froxlorCliBin} froxlor:config-services -a '{"http":"x","dns":"x","smtp":"x","mail":"x","antispam":"rspamd","ftp":"x","distro":"{$currentDistro}","system":[]}'
EOC;
Update::lastStepStatus(
1,
'manual action needed',
"Please run the following command manually as root:<br><pre>" . $manual_command . "</pre>"
);
} else {
Update::showUpdateStep("Removing existing domainkeys because antispam is disabled");
Database::query("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `dkim` = '0', `dkim_id` = '0', `dkim_privkey` = '', `dkim_pubkey` = '' WHERE `dkim` = '1';");
Update::lastStepStatus(1, '!!!');
}
Update::showUpdateStep("Enhancing admin and user table");
Database::query("ALTER TABLE `" . TABLE_PANEL_ADMINS . "` ADD `gui_access` tinyint(1) NOT NULL default '1';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `gui_access` tinyint(1) NOT NULL default '1';");
Update::lastStepStatus(0);
$to_clean = [
'actions/admin/settings/180.dkim.php',
'actions/admin/settings/185.spf.php',
];
Update::cleanOldFiles($to_clean);
Froxlor::updateToDbVersion('202312230');
Froxlor::updateToVersion('2.2.0-dev1');
}
if (Froxlor::isDatabaseVersion('202312230')) {
Update::showUpdateStep("Adding new settings");
Settings::AddNew("system.le_renew_services", "");
Settings::AddNew("system.le_renew_hook", "systemctl restart postfix dovecot proftpd");
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202401090');
}
if (Froxlor::isFroxlorVersion('2.2.0-dev1')) {
Update::showUpdateStep("Updating from 2.2.0-dev1 to 2.2.0-rc1", false);
Froxlor::updateToVersion('2.2.0-rc1');
}
if (Froxlor::isDatabaseVersion('202401090')) {
Update::showUpdateStep("Adding new table for 2fa tokens");
Database::query("DROP TABLE IF EXISTS `panel_2fa_tokens`;");
$sql = "CREATE TABLE `panel_2fa_tokens` (
`id` int(11) NOT NULL auto_increment,
`selector` varchar(20) NOT NULL,
`token` varchar(200) NOT NULL,
`userid` int(11) NOT NULL default '0',
`valid_until` int(15) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;";
Database::query($sql);
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202407200');
}
if (Froxlor::isFroxlorVersion('2.2.0-rc1')) {
Update::showUpdateStep("Updating from 2.2.0-rc1 to 2.2.0-rc2", false);
Froxlor::updateToVersion('2.2.0-rc2');
}
if (Froxlor::isFroxlorVersion('2.2.0-rc2')) {
Update::showUpdateStep("Updating from 2.2.0-rc2 to 2.2.0-rc3", false);
Froxlor::updateToVersion('2.2.0-rc3');
}
if (Froxlor::isDatabaseVersion('202407200')) {
Update::showUpdateStep("Adjusting field in 2fa-token table");
Database::query("ALTER TABLE `panel_2fa_tokens` CHANGE COLUMN `selector` `selector` varchar(200) NOT NULL;");
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202408140');
}
if (Froxlor::isFroxlorVersion('2.2.0-rc3')) {
Update::showUpdateStep("Updating from 2.2.0-rc3 to 2.2.0 stable", false);
Froxlor::updateToVersion('2.2.0');
}
if (Froxlor::isFroxlorVersion('2.2.0')) {
Update::showUpdateStep("Updating from 2.2.0 to 2.2.1", false);
Froxlor::updateToVersion('2.2.1');
}
if (Froxlor::isDatabaseVersion('202408140')) {
Update::showUpdateStep("Adding new rewrite-subject field to email table");
Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `rewrite_subject` tinyint(1) NOT NULL default '1' AFTER `spam_tag_level`;");
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202409280');
}
if (Froxlor::isFroxlorVersion('2.2.1')) {
Update::showUpdateStep("Updating from 2.2.1 to 2.2.2", false);
Froxlor::updateToVersion('2.2.2');
}

View File

@@ -34,7 +34,7 @@ $return = [];
if (Update::versionInUpdate($current_db_version, '202004140')) {
$has_preconfig = true;
$description = 'Froxlor can now optionally validate the dns entries of domains that request Lets Encrypt certificates to reduce dns-related problems (e.g. freshly registered domain or updated a-record).';
$question = '<strong>Validate DNS of domains when using Lets Encrypt</strong>';
$question = '<strong>Validate DNS of domains when using Lets Encrypt&nbsp;';
$return['system_le_domain_dnscheck'] = [
'type' => 'checkbox',
'value' => 1,

View File

@@ -55,7 +55,6 @@ if (Froxlor::isFroxlor()) {
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_0.10.inc.php'));
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.0.inc.php'));
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.1.inc.php'));
include_once(FileDir::makeCorrectFile(dirname(__FILE__) . '/updates/froxlor/update_2.2.inc.php'));
// Check Froxlor - database integrity (only happens after all updates are done, so we know the db-layout is okay)
Update::showUpdateStep("Checking database integrity");

View File

@@ -193,8 +193,7 @@ class Ajax
UI::initTwig();
try {
$force = Request::get('force', 0);
$json_result = \Froxlor\Api\Commands\Froxlor::getLocal($this->userinfo, ['force' => $force])->checkUpdate();
$json_result = \Froxlor\Api\Commands\Froxlor::getLocal($this->userinfo)->checkUpdate();
$result = json_decode($json_result, true)['data'];
$result['full_version'] = Froxlor::getFullVersion();
$result['dbversion'] = Froxlor::DBVERSION;

View File

@@ -156,7 +156,7 @@ class GlobalSearch
],
'result_key' => 'domain_ace',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'domain_ace',
'href' => 'admin_domains.php?page=domains&searchfield=d.domain_ace&searchtext='
]
@@ -172,7 +172,7 @@ class GlobalSearch
'result_key' => 'ip',
'result_groupkey' => 'ip',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'ip',
'href' => 'admin_ipsandports.php?page=ipsandports&searchfield=ip&searchtext='
]
@@ -186,7 +186,7 @@ class GlobalSearch
],
'result_key' => 'id',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'name',
'href' => 'admin_plans.php?page=overview&searchfield=id&searchtext='
]
@@ -201,7 +201,7 @@ class GlobalSearch
],
'result_key' => 'id',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'description',
'href' => 'admin_phpsettings.php?page=overview&searchfield=id&searchtext='
]
@@ -215,7 +215,7 @@ class GlobalSearch
],
'result_key' => 'id',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'description',
'href' => 'admin_phpsettings.php?page=fpmdaemons&searchfield=id&searchtext='
]
@@ -234,7 +234,7 @@ class GlobalSearch
],
'result_key' => 'loginname',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'name',
'href' => 'admin_admins.php?page=admins&searchfield=loginname&searchtext='
]
@@ -252,7 +252,7 @@ class GlobalSearch
],
'result_key' => 'domain_ace',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'domain_ace',
'href' => 'customer_domains.php?page=domains&searchfield=d.domain_ace&searchtext='
]
@@ -266,7 +266,7 @@ class GlobalSearch
],
'result_key' => 'email',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'email',
'href' => 'customer_email.php?page=email_domain&domainid={domainid}&searchfield=m.email&searchtext='
]
@@ -279,7 +279,7 @@ class GlobalSearch
],
'result_key' => 'domain',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'domain',
'href' => 'customer_email.php?page=emails&searchfield=d.domain&searchtext='
]
@@ -293,7 +293,7 @@ class GlobalSearch
],
'result_key' => 'databasename',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'databasename',
'href' => 'customer_mysql.php?page=mysqls&searchfield=databasename&searchtext='
]
@@ -307,7 +307,7 @@ class GlobalSearch
],
'result_key' => 'username',
'result_format' => [
'title' => ['\\Froxlor\\Ajax\\GlobalSearch', 'getFieldFromResult'],
'title' => ['self', 'getFieldFromResult'],
'title_args' => 'username',
'href' => 'customer_ftp.php?page=accounts&searchfield=username&searchtext='
]

View File

@@ -140,18 +140,12 @@ class Admins extends ApiCommand implements ResourceEntity
* create a new admin user
*
* @param string $name
* required, name of the adminstrator
* @param string $email
* required, email address of the administrator
* @param string $new_loginname
* required, loginname/username of the administrator
* @param string $admin_password
* optional, default auto-generated
* @param string $def_language
* * optional, ISO 639-1 language code (e.g. 'en', 'de', see lng-folder for supported languages),
* * default is system-default language
* @param bool $gui_access
* optional, allow login via webui, if false ONLY the login via webui is disallowed; default true
* 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
@@ -225,7 +219,6 @@ class Admins extends ApiCommand implements ResourceEntity
// parameters
$def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage'));
$gui_access = $this->getBoolParam('gui_access', true, true);
$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);
@@ -323,7 +316,6 @@ class Admins extends ApiCommand implements ResourceEntity
'name' => $name,
'email' => $email,
'lang' => $def_language,
'gui_access' => $gui_access,
'api_allowed' => $api_allowed,
'change_serversettings' => $change_serversettings,
'customers' => $customers,
@@ -352,7 +344,6 @@ class Admins extends ApiCommand implements ResourceEntity
`name` = :name,
`email` = :email,
`def_language` = :lang,
`gui_access` = :gui_access,
`api_allowed` = :api_allowed,
`change_serversettings` = :change_serversettings,
`customers` = :customers,
@@ -439,10 +430,7 @@ class Admins extends ApiCommand implements ResourceEntity
* @param string $admin_password
* optional, default auto-generated
* @param string $def_language
* * optional, ISO 639-1 language code (e.g. 'en', 'de', see lng-folder for supported languages),
* * default is system-default language
* @param bool $gui_access
* * optional, allow login via webui, if false ONLY the login via webui is disallowed; default true
* 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
@@ -536,7 +524,6 @@ class Admins extends ApiCommand implements ResourceEntity
// you cannot edit some of the details of yourself
if ($result['adminid'] == $this->getUserDetail('adminid')) {
$gui_access = $result['gui_access'];
$api_allowed = $result['api_allowed'];
$deactivated = $result['deactivated'];
$customers = $result['customers'];
@@ -555,7 +542,6 @@ class Admins extends ApiCommand implements ResourceEntity
$traffic = $result['traffic'];
$ipaddress = ($result['ip'] != -1 ? json_decode($result['ip'], true) : -1);
} else {
$gui_access = $this->getBoolParam('gui_access', true, $result['gui_access']);
$api_allowed = $this->getBoolParam('api_allowed', true, $result['api_allowed']);
$deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']);
@@ -679,7 +665,6 @@ class Admins extends ApiCommand implements ResourceEntity
'name' => $name,
'email' => $email,
'lang' => $def_language,
'gui_access' => $gui_access,
'api_allowed' => $api_allowed,
'change_serversettings' => $change_serversettings,
'customers' => $customers,
@@ -709,7 +694,6 @@ class Admins extends ApiCommand implements ResourceEntity
`name` = :name,
`email` = :email,
`def_language` = :lang,
`gui_access` = :gui_access,
`api_allowed` = :api_allowed,
`change_serversettings` = :change_serversettings,
`customers` = :customers,

View File

@@ -171,7 +171,6 @@ class Customers extends ApiCommand implements ResourceEntity
* create a new customer with default ftp-user and standard-subdomain (if wanted)
*
* @param string $email
* required, email address of new customer
* @param string $name
* optional if company is set, else required
* @param string $firstname
@@ -190,11 +189,8 @@ class Customers extends ApiCommand implements ResourceEntity
* optional
* @param int $customernumber
* optional
* @param string $def_language
* optional, ISO 639-1 language code (e.g. 'en', 'de', see lng-folder for supported languages),
* default is system-default language
* @param bool $gui_access
* optional, allow login via webui, if false ONLY the login via webui is disallowed; default true
* @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
@@ -275,7 +271,7 @@ class Customers extends ApiCommand implements ResourceEntity
* optional, specify a hosting-plan to set certain resource-values from the plan
* instead of specifying them
* @param array $allowed_mysqlserver
* optional, array of IDs of defined mysql-servers the customer is allowed to use,
* optional, array of IDs of defined mysql-servers the customer is allowed to use,
* default is to allow the default dbserver (id=0)
*
* @access admin
@@ -301,7 +297,6 @@ class Customers extends ApiCommand implements ResourceEntity
$fax = $this->getParam('fax', true, '');
$customernumber = $this->getParam('customernumber', true, '');
$def_language = $this->getParam('def_language', true, Settings::Get('panel.standardlanguage'));
$gui_access = $this->getBoolParam('gui_access', true, 1);
$api_allowed = $this->getBoolParam('api_allowed', true, (Settings::Get('api.enabled') && Settings::Get('api.customer_default')));
$gender = (int)$this->getParam('gender', true, 0);
$custom_notes = $this->getParam('custom_notes', true, '');
@@ -412,7 +407,7 @@ class Customers extends ApiCommand implements ResourceEntity
}
$allowed_mysqlserver = array();
if (!empty($p_allowed_mysqlserver) && is_array($p_allowed_mysqlserver)) {
if (! empty($p_allowed_mysqlserver) && is_array($p_allowed_mysqlserver)) {
foreach ($p_allowed_mysqlserver as $allowed_ms) {
$allowed_ms = intval($allowed_ms);
$allowed_mysqlserver[] = $allowed_ms;
@@ -460,28 +455,6 @@ class Customers extends ApiCommand implements ResourceEntity
if (function_exists('posix_getpwnam') && !in_array("posix_getpwnam", explode(",", ini_get('disable_functions'))) && posix_getpwnam($loginname)) {
Response::standardError('loginnameissystemaccount', $loginname, true);
}
// blacklist some system-internal names that might lead to issues
Database::needSqlData();
$sqldata = Database::getSqlData();
Database::needRoot(true);
Database::needSqlData();
$sqlrdata = Database::getSqlData();
$login_blacklist = [
'root',
'admin',
'froxroot',
'froxlor',
$sqldata['user'],
$sqldata['db'],
$sqlrdata['user'],
];
unset($sqldata);
unset($sqlrdata);
$login_blacklist = array_unique($login_blacklist);
if (in_array($loginname, $login_blacklist)) {
Response::standardError('loginnameisreservedname', $loginname, true);
}
} else {
$accountnumber = intval(Settings::Get('system.lastaccountnumber')) + 1;
$loginname = Settings::Get('customer.accountprefix') . $accountnumber;
@@ -545,7 +518,6 @@ class Customers extends ApiCommand implements ResourceEntity
'email' => $email,
'customerno' => $customernumber,
'lang' => $def_language,
'gui_access' => $gui_access,
'api_allowed' => $api_allowed,
'docroot' => $documentroot,
'guid' => $guid,
@@ -588,7 +560,6 @@ class Customers extends ApiCommand implements ResourceEntity
`email` = :email,
`customernumber` = :customerno,
`def_language` = :lang,
`gui_access` = :gui_access,
`api_allowed` = :api_allowed,
`documentroot` = :docroot,
`guid` = :guid,
@@ -738,12 +709,11 @@ class Customers extends ApiCommand implements ResourceEntity
'adminid' => $this->getUserDetail('adminid'),
'docroot' => $documentroot,
'phpenabled' => $phpenabled,
'openbasedir' => '1',
'is_stdsubdomain' => 1
'openbasedir' => '1'
];
$domainid = -1;
try {
$std_domain = $this->apiCall('Domains.add', $ins_data, true);
$std_domain = $this->apiCall('Domains.add', $ins_data);
$domainid = $std_domain['id'];
} catch (Exception $e) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_ERR, "[API] Unable to add standard-subdomain: " . $e->getMessage());
@@ -762,22 +732,6 @@ class Customers extends ApiCommand implements ResourceEntity
}
}
// Create default mysql-user if enabled
if ($mysqls != 0) {
foreach ($allowed_mysqlserver as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($this->logger());
// give permission to the user on every access-host we have
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$dbm->getManager()->grantPrivilegesTo($loginname, $password, $mysql_access_host, false, false, true);
}
$dbm->getManager()->flushPrivileges();
Database::needRoot(false);
}
}
if ($sendpassword == '1') {
$srv_hostname = Settings::Get('system.hostname');
if (Settings::Get('system.froxlordirectlyviahostname') == '0') {
@@ -977,7 +931,6 @@ class Customers extends ApiCommand implements ResourceEntity
* @param string $loginname
* optional, the loginname
* @param string $email
* optional
* @param string $name
* optional if company is set, else required
* @param string $firstname
@@ -996,11 +949,8 @@ class Customers extends ApiCommand implements ResourceEntity
* optional
* @param int $customernumber
* optional
* @param string $def_language
* * optional, ISO 639-1 language code (e.g. 'en', 'de', see lng-folder for supported languages),
* * default is system-default language
* @param bool $gui_access
* optional, allow login via webui, if false ONLY the login via webui is disallowed; default true
* @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
@@ -1011,7 +961,7 @@ class Customers extends ApiCommand implements ResourceEntity
* optional, whether to show the content of custom_notes to the customer, default 0
* (false)
* @param string $new_customer_password
* optional, set new password
* optional, iset new password
* @param bool $sendpassword
* optional, whether to send the password to the customer after creation, default 0
* (false)
@@ -1079,7 +1029,7 @@ class Customers extends ApiCommand implements ResourceEntity
* @param string $theme
* optional, change theme
* @param array $allowed_mysqlserver
* optional, array of IDs of defined mysql-servers the customer is allowed to use,
* optional, array of IDs of defined mysql-servers the customer is allowed to use,
* default is to allow the default dbserver (id=0)
*
* @access admin, customer
@@ -1115,7 +1065,6 @@ class Customers extends ApiCommand implements ResourceEntity
$fax = $this->getParam('fax', true, $result['fax']);
$customernumber = $this->getParam('customernumber', true, $result['customernumber']);
$def_language = $this->getParam('def_language', true, $result['def_language']);
$gui_access = $this->getBoolParam('gui_access', true, $result['gui_access']);
$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']);
@@ -1178,7 +1127,7 @@ class Customers extends ApiCommand implements ResourceEntity
if ($result['mysqls'] == 0 && ($mysqls == -1 || $mysqls > 0)) {
$allowed_mysqlserver = $this->getParam('allowed_mysqlserver', true, [0]);
}
if (!empty($allowed_mysqlserver)) {
if (! empty($allowed_mysqlserver)) {
$allowed_mysqlserver = array_map('intval', $allowed_mysqlserver);
}
@@ -1336,34 +1285,12 @@ class Customers extends ApiCommand implements ResourceEntity
]);
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `deactivated`= :deactivated WHERE `customerid` = :customerid
");
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `deactivated`= :deactivated WHERE `customerid` = :customerid");
Database::pexecute($upd_stmt, [
'deactivated' => $deactivated,
'customerid' => $id
]);
// enable/disable global mysql-user (loginname)
$current_allowed_mysqlserver = isset($result['allowed_mysqlserver']) && !empty($result['allowed_mysqlserver']) ? json_decode($result['allowed_mysqlserver'], true) : [];
foreach ($current_allowed_mysqlserver as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($this->logger());
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
// Prevent access, if deactivated
if ($deactivated) {
// failsafe if user has been deleted manually (requires MySQL 4.1.2+)
$dbm->getManager()->disableUser($result['loginname'], $mysql_access_host);
} else {
// Otherwise grant access
$dbm->getManager()->enableUser($result['loginname'], $mysql_access_host, true);
}
}
$dbm->getManager()->flushPrivileges();
Database::needRoot(false);
}
// Retrieve customer's databases
$databases_stmt = Database::prepare("SELECT * FROM " . TABLE_PANEL_DATABASES . " WHERE customerid = :customerid ORDER BY `dbserver`");
Database::pexecute($databases_stmt, [
@@ -1384,7 +1311,9 @@ class Customers extends ApiCommand implements ResourceEntity
$last_dbserver = $row_database['dbserver'];
}
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
foreach (array_unique(explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$mysql_access_host = trim($mysql_access_host);
// Prevent access, if deactivated
if ($deactivated) {
// failsafe if user has been deleted manually (requires MySQL 4.1.2+)
@@ -1473,7 +1402,6 @@ class Customers extends ApiCommand implements ResourceEntity
'logviewenabled' => $logviewenabled,
'custom_notes' => $custom_notes,
'custom_notes_show' => $custom_notes_show,
'gui_access' => $gui_access,
'api_allowed' => $api_allowed,
'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver)
];
@@ -1517,7 +1445,6 @@ class Customers extends ApiCommand implements ResourceEntity
`logviewenabled` = :logviewenabled,
`custom_notes` = :custom_notes,
`custom_notes_show` = :custom_notes_show,
`gui_access` = :gui_access,
`api_allowed` = :api_allowed,
`allowed_mysqlserver` = :allowed_mysqlserver";
$upd_query .= $admin_upd_query;
@@ -1675,21 +1602,6 @@ class Customers extends ApiCommand implements ResourceEntity
]);
$id = $result['customerid'];
// remove global mysql-user (loginname)
$current_allowed_mysqlserver = isset($result['allowed_mysqlserver']) && !empty($result['allowed_mysqlserver']) ? json_decode($result['allowed_mysqlserver'], true) : [];
foreach ($current_allowed_mysqlserver as $dbserver) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver, false);
// get DbManager
$dbm = new DbManager($this->logger());
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$dbm->getManager()->deleteUser($result['loginname'], $mysql_access_host);
}
$dbm->getManager()->flushPrivileges();
Database::needRoot(false);
}
// remove all databases
$databases_stmt = Database::prepare("
SELECT * FROM `" . TABLE_PANEL_DATABASES . "`
WHERE `customerid` = :id ORDER BY `dbserver`
@@ -1705,8 +1617,8 @@ class Customers extends ApiCommand implements ResourceEntity
$priv_changed = false;
while ($row_database = $databases_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($last_dbserver != $row_database['dbserver']) {
$dbm->getManager()->flushPrivileges();
Database::needRoot(true, $row_database['dbserver']);
$dbm->getManager()->flushPrivileges();
$last_dbserver = $row_database['dbserver'];
}
$dbm->getManager()->deleteDatabase($row_database['databasename']);

View File

@@ -115,7 +115,7 @@ class DomainZones extends ApiCommand implements ResourceEntity
// validation
$errors = [];
if (empty(trim($record))) {
if (empty($record)) {
$record = "@";
}
@@ -227,7 +227,7 @@ class DomainZones extends ApiCommand implements ResourceEntity
// remove it for checks
$content = substr($content, 0, -1);
}
if (!empty($content) && !Validate::validateDomain($content)) {
if (!Validate::validateDomain($content)) {
$errors[] = lng('error.dns_mx_needdom');
} else {
// check whether there is a CNAME-record for the same resource
@@ -244,10 +244,6 @@ class DomainZones extends ApiCommand implements ResourceEntity
}
// append trailing dot (again)
$content .= '.';
// if content is only ".", the prio needs to be 0 which results in a "null mx" entry
if ($content == '.' && $prio != 0) {
$prio = 0;
}
} elseif ($type == 'NS') {
// check for trailing dot
if (substr($content, -1) == '.') {

View File

@@ -274,8 +274,7 @@ class Domains extends ApiCommand implements ResourceEntity
* $override_tls is true
* @param string $description
* optional custom description (currently not used/shown in the frontend), default empty
* @param bool $is_stdsubdomain (internally)
* optional whether this is a standard subdomain for a customer which is being added so no usage is decreased
*
* @access admin
* @return string json-encoded array
* @throws Exception
@@ -283,8 +282,7 @@ class Domains extends ApiCommand implements ResourceEntity
public function add()
{
if ($this->isAdmin()) {
$is_stdsubdomain = $this->isInternal() ? $this->getBoolParam('is_stdsubdomain', true, 0) : false;
if ($is_stdsubdomain || $this->getUserDetail('domains_used') < $this->getUserDetail('domains') || $this->getUserDetail('domains') == '-1') {
if ($this->getUserDetail('domains_used') < $this->getUserDetail('domains') || $this->getUserDetail('domains') == '-1') {
// parameters
$p_domain = $this->getParam('domain');
@@ -797,15 +795,12 @@ class Domains extends ApiCommand implements ResourceEntity
$ins_data['id'] = $domainid;
unset($ins_data);
if (!$is_stdsubdomain) {
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_ADMINS . "` SET `domains_used` = `domains_used` + 1
WHERE `adminid` = :adminid
");
Database::pexecute($upd_stmt, [
'adminid' => $adminid
], true, true);
}
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_ADMINS . "` SET `domains_used` = `domains_used` + 1
WHERE `adminid` = :adminid");
Database::pexecute($upd_stmt, [
'adminid' => $adminid
], true, true);
$ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_DOMAINTOIP . "` SET
@@ -836,9 +831,6 @@ class Domains extends ApiCommand implements ResourceEntity
Cronjob::inserttask(TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
Cronjob::inserttask(TaskId::REBUILD_DNS);
if ($dkim == '1') {
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
}
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added domain '" . $domain . "'");
@@ -1416,7 +1408,7 @@ class Domains extends ApiCommand implements ResourceEntity
$zonefile = $result['zonefile'];
}
if (Settings::Get('antispam.activated') != '1') {
if (Settings::Get('dkim.use_dkim') != '1') {
$dkim = $result['dkim'];
}
@@ -1683,10 +1675,6 @@ class Domains extends ApiCommand implements ResourceEntity
Cronjob::inserttask(TaskId::REBUILD_VHOST);
}
if ($dkim != $result['dkim']) {
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
}
if ($speciallogfile != $result['speciallogfile'] && $speciallogverified != '1') {
$speciallogfile = $result['speciallogfile'];
}
@@ -2110,8 +2098,6 @@ class Domains extends ApiCommand implements ResourceEntity
* @param bool $is_stdsubdomain
* optional, default false, specify whether it's a std-subdomain you are deleting as it does not count
* as subdomain-resource
* @param bool $delete_userfiles
* optional, delete email account files on filesystem (if any), default false
*
* @access admin
* @return string json-encoded array
@@ -2123,8 +2109,7 @@ class Domains extends ApiCommand implements ResourceEntity
$id = $this->getParam('id', true, 0);
$dn_optional = $id > 0;
$domainname = $this->getParam('domainname', $dn_optional, '');
$is_stdsubdomain = $this->getBoolParam('is_stdsubdomain', true, 0);
$delete_user_emailfiles = $this->getBoolParam('delete_userfiles', true, 0);
$is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0);
$result = $this->apiCall('Domains.get', [
'id' => $id,
@@ -2148,14 +2133,6 @@ class Domains extends ApiCommand implements ResourceEntity
$idString = implode(' OR ', $idString);
if ($idString != '') {
if ($delete_user_emailfiles) {
// determine all connected email-accounts
$emailaccount_sel = Database::prepare("SELECT `email`, `homedir`, `maildir` FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString);
Database::pexecute($emailaccount_sel, $paramString, true, true);
while ($emailacc_row = $emailaccount_sel->fetch(PDO::FETCH_ASSOC)) {
Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $emailacc_row['email'], FileDir::makeCorrectDir($emailacc_row['homedir'] . '/' . $emailacc_row['maildir']));
}
}
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString);
Database::pexecute($del_stmt, $paramString, true, true);

View File

@@ -523,7 +523,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
$result = $this->apiCall('Emails.get', [
'id' => $id,
'emailaddr' => $emailaddr
], true);
]);
$id = $result['id'];
if (empty($result['popaccountid']) || $result['popaccountid'] == 0) {
@@ -563,7 +563,7 @@ class EmailAccounts extends ApiCommand implements ResourceEntity
}
if ($delete_userfiles) {
Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], FileDir::makeCorrectDir($result['homedir'] . '/' . $result['maildir']));
Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], $result['email_full']);
}
// decrease usage for customer

View File

@@ -69,7 +69,7 @@ class EmailDomains extends ApiCommand implements ResourceEntity
$result = [];
$query_fields = [];
$result_stmt = Database::prepare("
SELECT DISTINCT d.domain, d.domain_ace, e.domainid,
SELECT DISTINCT d.domain, e.domainid,
COUNT(e.email) as addresses,
IFNULL(SUM(CASE WHEN e.popaccountid > 0 THEN 1 ELSE 0 END), 0) as accounts,
IFNULL(SUM(

View File

@@ -28,12 +28,10 @@ namespace Froxlor\Api\Commands;
use Exception;
use Froxlor\Api\ApiCommand;
use Froxlor\Api\ResourceEntity;
use Froxlor\Cron\TaskId;
use Froxlor\Database\Database;
use Froxlor\FroxlorLogger;
use Froxlor\Idna\IdnaWrapper;
use Froxlor\Settings;
use Froxlor\System\Cronjob;
use Froxlor\UI\Response;
use Froxlor\Validate\Validate;
use PDO;
@@ -51,16 +49,6 @@ class Emails extends ApiCommand implements ResourceEntity
* name of the address before @
* @param string $domain
* domain-name for the email-address
* @param float $spam_tag_level
* optional, score which is required to tag emails as spam, default: 7.0
* @param bool $rewrite_subject
* optional, whether to add ***SPAM*** to the email's subject if applicable, default true
* @param float $spam_kill_level
* optional, score which is required to discard emails, default: 14.0
* @param boolean $bypass_spam
* optional, disable spam-filter entirely, default: no
* @param boolean $policy_greylist
* optional, enable grey-listing, default: yes
* @param boolean $iscatchall
* optional, make this address a catchall address, default: no
* @param int $customerid
@@ -86,20 +74,14 @@ class Emails extends ApiCommand implements ResourceEntity
$domain = $this->getParam('domain');
// parameters
$spam_tag_level = $this->getParam('spam_tag_level', true, '7.0');
$rewrite_subject = $this->getBoolParam('rewrite_subject', true, 1);
$spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, '14.0');
$bypass_spam = $this->getBoolParam('bypass_spam', true, 0);
$policy_greylist = $this->getBoolParam('policy_greylist', true, 1);
$iscatchall = $this->getBoolParam('iscatchall', true, 0);
$description = $this->getParam('description', true, '');
// validation
$idna_convert = new IdnaWrapper();
if (substr($domain, 0, 4) != 'xn--') {
$idna_convert = new IdnaWrapper();
$domain = $idna_convert->encode(Validate::validate($domain, 'domain', '', '', [], true));
}
$email_part = $idna_convert->encode($email_part);
// check domain and whether it's an email-enabled domain
// use internal call because the customer might have 'domains' in customer_hide_options
@@ -107,10 +89,10 @@ class Emails extends ApiCommand implements ResourceEntity
'domainname' => $domain
], true);
if ((int)$domain_check['isemaildomain'] == 0) {
Response::standardError('maindomainnonexist', $idna_convert->decode($domain), true);
Response::standardError('maindomainnonexist', $domain, true);
}
if ((int)$domain_check['deactivated'] == 1) {
Response::standardError('maindomaindeactivated', $idna_convert->decode($domain), true);
Response::standardError('maindomaindeactivated', $domain, true);
}
if (Settings::Get('catchall.catchall_enabled') != '1') {
@@ -131,7 +113,7 @@ class Emails extends ApiCommand implements ResourceEntity
// validate it
if (!Validate::validateEmail($email_full)) {
Response::standardError('emailiswrong', $idna_convert->decode($email_full), true);
Response::standardError('emailiswrong', $email_full, true);
}
// get needed customer info to reduce the email-address-counter by one
@@ -152,28 +134,17 @@ class Emails extends ApiCommand implements ResourceEntity
if ($email_check) {
if (strtolower($email_check['email_full']) == strtolower($email_full)) {
Response::standardError('emailexistalready', $idna_convert->decode($email_full), true);
Response::standardError('emailexistalready', $email_full, true);
} elseif ($email_check['email'] == $email) {
Response::standardError('youhavealreadyacatchallforthisdomain', '', true);
}
}
$spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1})?$/', '', [7.0], true);
if ($spam_kill_level > -1) {
$spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1})?$/', '', [14.0], true);
}
$description = Validate::validate(trim($description), 'description', Validate::REGEX_DESC_TEXT, '', [], true);
$stmt = Database::prepare("
INSERT INTO `" . TABLE_MAIL_VIRTUAL . "` SET
`customerid` = :cid,
`email` = :email,
`email_full` = :email_full,
`spam_tag_level` = :spam_tag_level,
`rewrite_subject` = :rewrite_subject,
`spam_kill_level` = :spam_kill_level,
`bypass_spam` = :bypass_spam,
`policy_greylist` = :policy_greylist,
`iscatchall` = :iscatchall,
`domainid` = :domainid,
`description` = :description
@@ -182,11 +153,6 @@ class Emails extends ApiCommand implements ResourceEntity
"cid" => $customer['customerid'],
"email" => $email,
"email_full" => $email_full,
"spam_tag_level" => $spam_tag_level,
"rewrite_subject" => $rewrite_subject,
"spam_kill_level" => $spam_kill_level,
"bypass_spam" => $bypass_spam,
"policy_greylist" => $policy_greylist,
"iscatchall" => $iscatchall,
"domainid" => $domain_check['id'],
"description" => $description
@@ -196,7 +162,6 @@ class Emails extends ApiCommand implements ResourceEntity
// update customer usage
Customers::increaseUsage($customer['customerid'], 'emails_used');
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added email address '" . $email_full . "'");
$result = $this->apiCall('Emails.get', [
@@ -229,12 +194,12 @@ class Emails extends ApiCommand implements ResourceEntity
$customer_ids = $this->getAllowedCustomerIds('email');
$params['idea'] = ($id <= 0 ? $emailaddr : $id);
$result_stmt = Database::prepare("SELECT v.*, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize` " . ($this->isInternal() ? ", `u`.`homedir`, `u`.`maildir`" : "") . "
$result_stmt = Database::prepare("SELECT v.`id`, v.`email`, v.`email_full`, v.`iscatchall`, v.`destination`, v.`customerid`, v.`popaccountid`, v.`domainid`, v.`description`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
FROM `" . TABLE_MAIL_VIRTUAL . "` v
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
AND " . (is_numeric($params['idea']) ? "v.`id`= :idea" : "(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_INFO, "[API] get email address '" . $result['email_full'] . "'");
@@ -255,16 +220,6 @@ class Emails extends ApiCommand implements ResourceEntity
* optional, required when called as admin (if $loginname is not specified)
* @param string $loginname
* optional, required when called as admin (if $customerid is not specified)
* @param float $spam_tag_level
* optional, score which is required to tag emails as spam, default: 7.0
* @param bool $rewrite_subject
* optional, whether to add ***SPAM*** to the email's subject if applicable, default true
* @param float $spam_kill_level
* optional, score which is required to discard emails, default: 14.0
* @param boolean $bypass_spam
* optional, disable spam-filter entirely, default: no
* @param boolean $policy_greylist
* optional, enable grey-listing, default: yes
* @param boolean $iscatchall
* optional
* @param string $description
@@ -280,6 +235,15 @@ class Emails extends ApiCommand implements ResourceEntity
throw new Exception("You cannot access this resource", 405);
}
// if enabling catchall is not allowed by settings, we do not need
// to run update()
if (Settings::Get('catchall.catchall_enabled') != '1') {
Response::standardError([
'operationnotpermitted',
'featureisdisabled'
], 'catchall', true);
}
$id = $this->getParam('id', true, 0);
$ea_optional = $id > 0;
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
@@ -291,83 +255,48 @@ class Emails extends ApiCommand implements ResourceEntity
$id = $result['id'];
// parameters
$spam_tag_level = $this->getParam('spam_tag_level', true, $result['spam_tag_level']);
$rewrite_subject = $this->getBoolParam('rewrite_subject', true, $result['rewrite_subject']);
$spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, $result['spam_kill_level']);
$bypass_spam = $this->getBoolParam('bypass_spam', true, $result['bypass_spam']);
$policy_greylist = $this->getBoolParam('policy_greylist', true, $result['policy_greylist']);
$iscatchall = $this->getBoolParam('iscatchall', true, $result['iscatchall']);
$description = $this->getParam('description', true, $result['description']);
// if enabling catchall is not allowed by settings, we do not need
// to run update()
if ($iscatchall && $result['iscatchall'] == 0 && Settings::Get('catchall.catchall_enabled') != '1') {
Response::standardError([
'operationnotpermitted',
'featureisdisabled'
], 'catchall', true);
}
// get needed customer info to reduce the email-address-counter by one
$customer = $this->getCustomerData();
// check for catchall-flag
$email = $result['email_full'];
if ($iscatchall) {
$iscatchall = '1';
$email = $result['email'];
// update only required if it was not a catchall before
if ($result['iscatchall'] == 0) {
$email_parts = explode('@', $result['email_full']);
$email = '@' . $email_parts[1];
// catchall check
$stmt = Database::prepare("
SELECT `email_full` FROM `" . TABLE_MAIL_VIRTUAL . "`
WHERE `email` = :email AND `customerid` = :cid AND `iscatchall` = '1'
");
$params = [
"email" => $email,
"cid" => $customer['customerid']
];
$email_check = Database::pexecute_first($stmt, $params, true, true);
if ($email_check) {
Response::standardError('youhavealreadyacatchallforthisdomain', '', true);
}
$email_parts = explode('@', $result['email_full']);
$email = '@' . $email_parts[1];
// catchall check
$stmt = Database::prepare("
SELECT `email_full` FROM `" . TABLE_MAIL_VIRTUAL . "`
WHERE `email` = :email AND `customerid` = :cid AND `iscatchall` = '1'
");
$params = [
"email" => $email,
"cid" => $customer['customerid']
];
$email_check = Database::pexecute_first($stmt, $params, true, true);
if ($email_check) {
Response::standardError('youhavealreadyacatchallforthisdomain', '', true);
}
} else {
$iscatchall = '0';
$email = $result['email_full'];
}
$spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1,2})?$/', '', [7.0], true);
if ($spam_kill_level > -1) {
$spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1,2})?$/', '', [14.0], true);
}
$description = Validate::validate(trim($description), 'description', Validate::REGEX_DESC_TEXT, '', [], true);
$stmt = Database::prepare("
UPDATE `" . TABLE_MAIL_VIRTUAL . "` SET
`email` = :email ,
`spam_tag_level` = :spam_tag_level,
`rewrite_subject` = :rewrite_subject,
`spam_kill_level` = :spam_kill_level,
`bypass_spam` = :bypass_spam,
`policy_greylist` = :policy_greylist,
`iscatchall` = :caflag,
`description` = :description
UPDATE `" . TABLE_MAIL_VIRTUAL . "`
SET `email` = :email , `iscatchall` = :caflag, `description` = :description
WHERE `customerid`= :cid AND `id`= :id
");
$params = [
"email" => $email,
"spam_tag_level" => $spam_tag_level,
"rewrite_subject" => $rewrite_subject,
"spam_kill_level" => $spam_kill_level,
"bypass_spam" => $bypass_spam,
"policy_greylist" => $policy_greylist,
"caflag" => $iscatchall,
"description" => $description,
"cid" => $customer['customerid'],
"id" => $id
];
Database::pexecute($stmt, $params, true, true);
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] toggled catchall-flag for email address '" . $result['email_full'] . "'");
$result = $this->apiCall('Emails.get', [
@@ -405,16 +334,13 @@ class Emails extends ApiCommand implements ResourceEntity
$result = [];
$query_fields = [];
$result_stmt = Database::prepare("
SELECT m.*, d.`domain`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, m.`destination`, m.`popaccountid`, d.`domain`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
FROM `" . TABLE_MAIL_VIRTUAL . "` m
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`)
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`)
WHERE m.`customerid` IN (" . implode(", ", $customer_ids) . ")" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
Database::pexecute($result_stmt, $query_fields, true, true);
$idna_convert = new IdnaWrapper();
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$row['email'] = $idna_convert->decode($row['email']);
$row['email_full'] = $idna_convert->decode($row['email_full']);
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list email-addresses");

View File

@@ -54,7 +54,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
* @param string $description
* optional, description for database
* @param string $custom_suffix
* optional, name for database if customer.mysqlprefix setting is set to "DBNAME"
* optional, name for database
* @param bool $sendinfomail
* optional, send created resource-information to customer, default: false
* @param int $customerid
@@ -110,9 +110,6 @@ class Mysqls extends ApiCommand implements ResourceEntity
$dbm = new DbManager($this->logger());
if (strtoupper(Settings::Get('customer.mysqlprefix')) == 'DBNAME' && !empty($databasename)) {
if (strlen($newdb_params['loginname'] . '_' . $databasename) > Database::getSqlUsernameLength()) {
throw new Exception("Database name cannot be longer than " . (Database::getSqlUsernameLength() - strlen($newdb_params['loginname'] . '_')) . " characters.", 406);
}
$username = $dbm->createDatabase($newdb_params['loginname'] . '_' . $databasename, $password, $dbserver);
} else {
$username = $dbm->createDatabase($newdb_params['loginname'], $password, $dbserver, $newdb_params['mysql_lastaccountnumber']);

View File

@@ -983,11 +983,9 @@ class SubDomains extends ApiCommand implements ResourceEntity
'`d`.`letsencrypt`',
'`d`.`registration_date`',
'`d`.`termination_date`',
'`d`.`deactivated`',
'`d`.`email_only`',
'`d`.`deactivated`'
];
}
$query_fields = [];
// prepare select statement
@@ -998,6 +996,7 @@ class SubDomains extends ApiCommand implements ResourceEntity
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `da` ON `da`.`aliasdomain`=`d`.`id`
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` `pd` ON `pd`.`id`=`d`.`parentdomainid`
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
AND `d`.`email_only` = '0'
" . $this->getSearchWhere($query_fields, true) . " GROUP BY `d`.`id` ORDER BY `parentdomainname` ASC, `d`.`parentdomainid` ASC " . $this->getOrderBy(true) . $this->getLimit());
$result = [];
@@ -1093,13 +1092,13 @@ class SubDomains extends ApiCommand implements ResourceEntity
$this->getUserDetail('customerid')
];
}
if (!empty($customer_ids)) {
// prepare select statement
$domains_stmt = Database::prepare("
SELECT COUNT(*) as num_subdom
FROM `" . TABLE_PANEL_DOMAINS . "` `d`
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
AND `d`.`email_only` = '0'
");
$result = Database::pexecute_first($domains_stmt, null, true, true);
if ($result) {

View File

@@ -91,7 +91,7 @@ class SysLog extends ApiCommand implements ResourceEntity
Database::pexecute($result_stmt, $query_fields, true, true);
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
// clean log-text
$row['text'] = preg_replace("/[^\w @#\"':.,()\[\]+\-_\/\\\!]/i", "_", $row['text']);
$row['text'] = preg_replace("/[^\w @#\"':.()\[\]+\-_\/\\\!]/i", "_", $row['text']);
$result[] = $row;
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list log-entries");
@@ -225,7 +225,7 @@ class SysLog extends ApiCommand implements ResourceEntity
}
$params['trunc'] = $truncatedate;
Database::pexecute($result_stmt, $params, true, true);
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] truncated the froxlor syslog");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] truncated the froxlor syslog");
return $this->response(true);
}
throw new Exception("Not allowed to execute given command.", 403);

View File

@@ -43,10 +43,11 @@ final class ConfigServices extends CliCommand
{
private $yes_to_all_supported = [
'bookworm',
'bionic',
'bullseye',
'buster',
'focal',
'jammy',
'noble',
];
protected function configure()
@@ -171,8 +172,8 @@ final class ConfigServices extends CliCommand
$distributions_select_data = [];
//set default os.
$os_dist = ['ID' => 'bookworm'];
$os_version = ['0' => '12'];
$os_dist = ['ID' => 'bullseye'];
$os_version = ['0' => '11'];
$os_default = $os_dist['ID'];
//read os-release
@@ -217,10 +218,6 @@ final class ConfigServices extends CliCommand
$_daemons_config['distro'] = $io->choice('Choose distribution', $valid_dists, $os_default);
// go through all services and let user check whether to include it or not
if (empty($_daemons_config['distro']) || !file_exists($config_dir . '/' . $_daemons_config['distro']. ".xml")) {
$output->writeln('<error>Empty or non-existing distribution given.</>');
return self::INVALID;
}
$configfiles = new ConfigParser($config_dir . '/' . $_daemons_config['distro'] . ".xml");
$services = $configfiles->getServices();
@@ -356,13 +353,8 @@ final class ConfigServices extends CliCommand
}
if (!empty($decoded_config)) {
$config_dir = Froxlor::getInstallDir() . 'lib/configfiles/';
if (empty($decoded_config['distro']) || !file_exists($config_dir . '/' . $decoded_config['distro']. ".xml")) {
$output->writeln('<error>Empty or non-existing distribution given. Please login with an admin, go to "System -> Configuration" and select your correct distribution in the top-right corner or specify valid distribution name for "distro" parameter.</>');
return self::INVALID;
}
$configfiles = new ConfigParser($config_dir . '/' . $decoded_config['distro']. ".xml");
$configfiles = new ConfigParser($config_dir . '/' . $decoded_config['distro'] . ".xml");
$services = $configfiles->getServices();
$replace_arr = $this->getReplacerArray();

View File

@@ -27,13 +27,10 @@ namespace Froxlor\Cli;
use Exception;
use Froxlor\Config\ConfigParser;
use Froxlor\Database\Database;
use Froxlor\Froxlor;
use Froxlor\Install\Install;
use Froxlor\Install\Install\Core;
use Froxlor\Settings;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -53,8 +50,7 @@ final class InstallCommand extends Command
$this->setDescription('Installation process to use instead of web-ui');
$this->addArgument('input-file', InputArgument::OPTIONAL, 'Optional JSON array file to use for unattended installations');
$this->addOption('print-example-file', 'p', InputOption::VALUE_NONE, 'Outputs an example JSON content to be used with the input file parameter')
->addOption('create-userdata-from-str', 'c', InputOption::VALUE_REQUIRED, 'Creates lib/userdata.inc.php file from string created by web-install process')
->addOption('show-sysinfo', 's', InputOption::VALUE_NONE, 'Outputs system information about your froxlor installation');
->addOption('create-userdata-from-str', 'c', InputOption::VALUE_REQUIRED, 'Creates lib/userdata.inc.php file from string created by web-install process');
}
/**
@@ -76,15 +72,6 @@ final class InstallCommand extends Command
return self::INVALID;
}
if ($input->getOption('show-sysinfo') !== false) {
if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) {
$output->writeln("<error>Could not find froxlor's userdata.inc.php file. You can use this parameter only with an installed froxlor system.</>");
return self::INVALID;
}
$this->printSysInfo($output);
return self::SUCCESS;
}
session_start();
require __DIR__ . '/install.functions.php';
@@ -362,57 +349,6 @@ final class InstallCommand extends Command
fclose($fp);
}
private function printSysInfo(OutputInterface $output)
{
$php_sapi = 'mod_php';
$php_version = phpversion();
if (Settings::Get('system.mod_fcgid') == '1') {
$php_sapi = 'FCGID';
if (Settings::Get('system.mod_fcgid_ownvhost') == '1') {
$php_sapi .= ' (+ froxlor)';
}
} elseif (Settings::Get('phpfpm.enabled') == '1') {
$php_sapi = 'PHP-FPM';
if (Settings::Get('phpfpm.enabled_ownvhost') == '1') {
$php_sapi .= ' (+ froxlor)';
}
}
$kernel = 'unknown';
if (function_exists('posix_uname')) {
$kernel_nfo = posix_uname();
$kernel = $kernel_nfo['release'] . ' (' . $kernel_nfo['machine'] . ')';
}
$ips = [];
$ips_stmt = Database::query("SELECT CONCAT(`ip`, ' (', `port`, ')') as ipaddr FROM `" . TABLE_PANEL_IPSANDPORTS . "` ORDER BY `id`");
while ($ip = $ips_stmt->fetch(\PDO::FETCH_ASSOC)) {
$ips[] = $ip['ipaddr'];
}
$table = new Table($output);
$table
->setHeaders([
'Key', 'Value'
])
->setRows([
['Froxlor', Froxlor::getVersionString()],
['Update-channel', Settings::Get('system.update_channel')],
['Hostname', Settings::Get('system.hostname')],
['Install-dir', Froxlor::getInstallDir()],
['PHP CLI', $php_version],
['PHP SAPI', $php_sapi],
['Webserver', Settings::Get('system.webserver')],
['Kernel', $kernel],
['Database', Database::getAttribute(\PDO::ATTR_SERVER_VERSION)],
['Distro config', Settings::Get('system.distribution')],
['IP addresses', implode("\n", $ips)],
]);
$table->setStyle('box');
$table->render();
}
private function cliTextFormat(string $text, string $nl_char = "\n"): string
{
$text = str_replace(['<br>', '<br/>', '<br />'], [$nl_char, $nl_char, $nl_char], $text);

View File

@@ -52,7 +52,7 @@ final class MasterCron extends CliCommand
$this->setName('froxlor:cron');
$this->setDescription('Regulary perform tasks created by froxlor');
$this->addArgument('job', InputArgument::IS_ARRAY, 'Job(s) to run');
$this->addOption('run-task', 'r', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Run a specific task [1 = re-generate configs, 4 = re-generate dns zones, 9 = re-generate rspamd configs, 10 = re-set quotas, 99 = re-create cron.d-file]')
$this->addOption('run-task', 'r', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Run a specific task [1 = re-generate configs, 4 = re-generate dns zones, 10 = re-set quotas, 99 = re-create cron.d-file]')
->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces given job or, if none given, forces re-generating of config-files (webserver, nameserver, etc.)')
->addOption('debug', 'd', InputOption::VALUE_NONE, 'Output debug information about what is going on to STDOUT.')
->addOption('no-fork', 'N', InputOption::VALUE_NONE, 'Do not fork to background (traffic cron only).');
@@ -77,7 +77,6 @@ final class MasterCron extends CliCommand
if (empty($jobs) || in_array('tasks', $jobs)) {
Cronjob::inserttask(TaskId::REBUILD_VHOST);
Cronjob::inserttask(TaskId::REBUILD_DNS);
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
Cronjob::inserttask(TaskId::CREATE_QUOTA);
Cronjob::inserttask(TaskId::REBUILD_CRON);
$jobs[] = 'tasks';
@@ -96,7 +95,7 @@ final class MasterCron extends CliCommand
if ($input->getOption('run-task')) {
$tasks_to_run = $input->getOption('run-task');
foreach ($tasks_to_run as $ttr) {
if (in_array($ttr, [TaskId::REBUILD_VHOST, TaskId::REBUILD_DNS, TaskId::REBUILD_RSPAMD, TaskId::CREATE_QUOTA, TaskId::REBUILD_CRON])) {
if (in_array($ttr, [TaskId::REBUILD_VHOST, TaskId::REBUILD_DNS, TaskId::CREATE_QUOTA, TaskId::REBUILD_CRON])) {
Cronjob::inserttask($ttr);
$jobs[] = 'tasks';
} else {
@@ -171,9 +170,8 @@ final class MasterCron extends CliCommand
FroxlorLogger::getInstanceOf()->setCronLog(0);
}
// clean up possible old login-links and 2fa tokens
// clean up possible old login-links
Database::query("DELETE FROM `" . TABLE_PANEL_LOGINLINKS . "` WHERE `valid_until` < UNIX_TIMESTAMP()");
Database::query("DELETE FROM `" . TABLE_PANEL_2FA_TOKENS . "` WHERE `valid_until` < UNIX_TIMESTAMP()");
return $result;
}

View File

@@ -28,17 +28,13 @@ namespace Froxlor\Cli;
use Exception;
use Froxlor\Froxlor;
use Froxlor\Install\AutoUpdate;
use Froxlor\Install\Preconfig;
use Froxlor\Install\Update;
use Froxlor\Settings;
use Froxlor\System\Mailer;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;
final class UpdateCommand extends CliCommand
{
@@ -48,8 +44,6 @@ final class UpdateCommand extends CliCommand
$this->setName('froxlor:update');
$this->setDescription('Check for newer version and update froxlor');
$this->addOption('check-only', 'c', InputOption::VALUE_NONE, 'Only check for newer version and exit')
->addOption('show-update-options', 'o', InputOption::VALUE_NONE, 'Show possible update option parameter for the update if any. Only usable in combination with "check-only".')
->addOption('update-options', 'O', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Parameter list of update options.')
->addOption('database', 'd', InputOption::VALUE_NONE, 'Only run database updates in case updates are done via apt or manually.')
->addOption('mail-notify', 'm', InputOption::VALUE_NONE, 'Additionally inform administrator via email if a newer version was found')
->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for download, extract and database-update, just do it (if not --check-only is set)')
@@ -64,18 +58,13 @@ final class UpdateCommand extends CliCommand
if ($input->getOption('database')) {
$result = $this->validateRequirements($output, true);
if ($result == self::SUCCESS) {
require Froxlor::getInstallDir() . '/lib/functions.php';
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
$output->writeln('<info>' . lng('update.dbupdate_required') . '</>');
$output->writeln('<info>' . lng('updates.dbupdate_required') . '</>');
if ($input->getOption('check-only')) {
$output->writeln('<comment>Doing nothing because of "check-only" flag.</>');
$this->askUpdateOptions($input, $output, null, false);
} else {
$yestoall = $input->getOption('yes-to-all') !== false;
$helper = $this->getHelper('question');
$this->askUpdateOptions($input, $output, $helper, $yestoall);
$question = new ConfirmationQuestion('Update database? [no] ', false, '/^(y|j)/i');
if ($yestoall || $helper->ask($input, $output, $question)) {
$result = $this->runUpdate($output, true);
@@ -111,7 +100,7 @@ final class UpdateCommand extends CliCommand
}
// there is a new version
if ($input->getOption('check-only')) {
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel') . ' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel').' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
} else {
$text = lng('admin.newerversionavailable') . ' ' . lng('admin.newerversiondetails', [AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
}
@@ -162,7 +151,6 @@ final class UpdateCommand extends CliCommand
// check whether we only wanted to check
if ($input->getOption('check-only')) {
//$output->writeln('<comment>Not proceeding as "check-only" is specified</>');
$this->askUpdateOptions($input, $output, null, false);
return $result;
} else {
$yestoall = $input->getOption('yes-to-all') !== false;
@@ -185,9 +173,6 @@ final class UpdateCommand extends CliCommand
if ($auex == 0) {
$output->writeln("<info>Froxlor files updated successfully.</>");
$result = self::SUCCESS;
$this->askUpdateOptions($input, $output, $helper, $yestoall);
$question = new ConfirmationQuestion('Update database? [no] ', false, '/^(y|j)/i');
if ($yestoall || $helper->ask($input, $output, $question)) {
$result = $this->runUpdate($output, true);
@@ -209,141 +194,12 @@ final class UpdateCommand extends CliCommand
return $result;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @param $helper
* @param bool $yestoall
* @return void
*/
private function askUpdateOptions(InputInterface $input, OutputInterface $output, $helper, bool $yestoall = false)
{
// check for preconfigs
$preconfig = Preconfig::getPreConfig(true);
$show_options_only = $input->getOption('show-update-options') !== false;
if (!is_null($helper) && $show_options_only) {
$output->writeln('<comment>Unsetting "show-update-options" due to not being called with "check-only".</>');
$show_options_only = false;
}
$update_options = [];
// set parameters
$uOptions = $input->getOption('update-options');
if (!empty($uOptions)) {
$options_value = [];
foreach ($uOptions as $givenOption) {
$optVal = explode("=", $givenOption);
if (count($optVal) == 2) {
$options_value[$optVal[0]] = $optVal[1];
}
}
}
if (!empty($preconfig)) {
krsort($preconfig);
foreach ($preconfig as $section) {
if (!$show_options_only) {
$output->writeln("<info>Updater questions for " . $section['title'] . "</>");
}
foreach ($section['fields'] as $update_field => $metainfo) {
if (isset($options_value[$update_field])) {
$output->writeln('Setting given parameter "' . $update_field . '" to "' . $options_value[$update_field] . '"');
$_POST[$update_field] = $options_value[$update_field];
continue;
}
$default = null;
$question_text = html_entity_decode(strip_tags($metainfo['label']), ENT_QUOTES | ENT_IGNORE, "UTF-8");
if ($metainfo['type'] == 'checkbox') {
$default = (int)$metainfo['checked'];
if ($show_options_only) {
$update_options[] = [
'name' => $update_field,
'question' => $question_text,
'default' => $default,
'choices' => '0: No' . PHP_EOL . '1: Yes' . PHP_EOL
];
} else {
$question = new ConfirmationQuestion($question_text . ' [' . ($metainfo['checked'] ? 'yes' : 'no') . '] ', (bool)$metainfo['checked'], '/^(y|j)/i');
}
} elseif ($metainfo['type'] == 'select') {
$default = $metainfo['selected'];
$choices = "";
foreach (array_values($metainfo['select_var'] ?? []) as $index => $choice) {
$choices .= $index . ': ' . $choice . PHP_EOL;
}
if ($show_options_only) {
$update_options[] = [
'name' => $update_field,
'question' => $question_text,
'default' => !empty($default) ? $default : '-',
'choices' => $choices
];
} else {
$question = new ChoiceQuestion(
$question_text,
array_values($metainfo['select_var'] ?? []),
$metainfo['selected']
);
$question->setValidator(function ($answer) use ($metainfo): string {
$key = array_keys($metainfo['select_var'])[(int)$answer] ?? false; // Find the key based on the selected value
if ($key === false) {
throw new \RuntimeException('Invalid selection.');
}
return $key;
});
}
} elseif ($metainfo['type'] == 'text') {
$default = $metainfo['value'] ?? '';
if ($show_options_only) {
$update_options[] = [
'name' => $update_field,
'question' => $question_text,
'default' => $default,
'choices' => PHP_EOL
];
} else {
$question = new Question($question_text . (!empty($metainfo['value']) ? ' [' . $metainfo['value'] . ']' : ''), $default);
$question->setValidator(function (string $answer) use ($metainfo): string {
if (($metainfo['mandatory'] ?? false) && empty($answer)) {
throw new \RuntimeException(
'Answer cannot be empty'
);
}
if (!empty($metainfo['pattern'] ?? "") && !preg_match("/" . $metainfo['pattern'] . "/", $answer)) {
throw new \RuntimeException('Answer does not seem to be in valid format');
}
return $answer;
});
}
} else {
$output->writeln("<error>Unknown type " . $metainfo['type'] . "</error>");
continue;
}
if (!$show_options_only) {
if ($yestoall) {
$_POST[$update_field] = $default;
} else {
$_POST[$update_field] = $helper->ask($input, $output, $question);
}
}
}
}
if ($show_options_only) {
$io = new SymfonyStyle($input, $output);
$io->table(
['Parameter', 'Description', 'Default', 'Choices'],
$update_options
);
}
}
}
private function mailNotify(InputInterface $input, OutputInterface $output)
{
if ($input->getOption('mail-notify')) {
$last_check_version = Settings::Get('system.update_notify_last');
if (Update::versionInUpdate($last_check_version, AutoUpdate::getFromResult('version'))) {
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel') . ' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
$text = lng('update.uc_newinfo', [(Settings::Get('system.update_channel') != 'stable' ? Settings::Get('system.update_channel').' ' : ''), AutoUpdate::getFromResult('version'), Froxlor::VERSION]);
$mail = new Mailer(true);
$mail->Body = $text;
$mail->Subject = "[froxlor] " . lng('update.notify_subject');

View File

@@ -91,9 +91,6 @@ class ConfigDaemon
$this->fullxml = $xml;
$this->xpath = $xpath;
$this->daemon = $this->fullxml->xpath($this->xpath);
if (count($this->daemon) !== 1) {
throw new Exception('XPath "' . $this->xpath . '" didn\'t return exactly one element');
}
$attributes = $this->daemon[0]->attributes();
if ($attributes['title'] != '') {
$this->title = $this->parseContent((string)$attributes['title']);
@@ -412,7 +409,7 @@ class ConfigDaemon
}
$return[] = [
'type' => 'command',
'content' => '[ -f ' . $this->parseContent($attributes['name']) . ' ] && ' . $cmd . ' "' . $this->parseContent($attributes['name']) . '" "' . $this->parseContent($attributes['name']) . '.frx.bak"',
'content' => $cmd . ' "' . $this->parseContent($attributes['name']) . '" "' . $this->parseContent($attributes['name']) . '.frx.bak"',
'execute' => "pre"
];
}

View File

@@ -117,6 +117,85 @@ abstract class DnsBase
}
}
public function writeDKIMconfigs()
{
if (Settings::Get('dkim.use_dkim') == '1') {
if (!file_exists(FileDir::makeCorrectDir(Settings::Get('dkim.dkim_prefix')))) {
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir(Settings::Get('dkim.dkim_prefix'))));
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir(Settings::Get('dkim.dkim_prefix'))));
}
$dkimdomains = '';
$dkimkeys = '';
$result_domains_stmt = Database::query("
SELECT `id`, `domain`, `dkim`, `dkim_id`, `dkim_pubkey`, `dkim_privkey`
FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `dkim` = '1' ORDER BY `id` ASC
");
while ($domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
$privkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . Settings::Get('dkim.privkeysuffix'));
$pubkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . '.public');
if ($domain['dkim_privkey'] == '' || $domain['dkim_pubkey'] == '') {
$max_dkim_id_stmt = Database::query("SELECT MAX(`dkim_id`) as `max_dkim_id` FROM `" . TABLE_PANEL_DOMAINS . "`");
$max_dkim_id = $max_dkim_id_stmt->fetch(PDO::FETCH_ASSOC);
$domain['dkim_id'] = (int)$max_dkim_id['max_dkim_id'] + 1;
$privkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . Settings::Get('dkim.privkeysuffix'));
FileDir::safe_exec('openssl genrsa -out ' . escapeshellarg($privkey_filename) . ' ' . Settings::Get('dkim.dkim_keylength'));
$domain['dkim_privkey'] = file_get_contents($privkey_filename);
FileDir::safe_exec("chmod 0640 " . escapeshellarg($privkey_filename));
$pubkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . '.public');
FileDir::safe_exec('openssl rsa -in ' . escapeshellarg($privkey_filename) . ' -pubout -outform pem -out ' . escapeshellarg($pubkey_filename));
$domain['dkim_pubkey'] = file_get_contents($pubkey_filename);
FileDir::safe_exec("chmod 0664 " . escapeshellarg($pubkey_filename));
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
`dkim_id` = :dkimid,
`dkim_privkey` = :privkey,
`dkim_pubkey` = :pubkey
WHERE `id` = :id
");
$upd_data = [
'dkimid' => $domain['dkim_id'],
'privkey' => $domain['dkim_privkey'],
'pubkey' => $domain['dkim_pubkey'],
'id' => $domain['id']
];
Database::pexecute($upd_stmt, $upd_data);
}
if (!file_exists($privkey_filename) && $domain['dkim_privkey'] != '') {
$privkey_file_handler = fopen($privkey_filename, "w");
fwrite($privkey_file_handler, $domain['dkim_privkey']);
fclose($privkey_file_handler);
FileDir::safe_exec("chmod 0640 " . escapeshellarg($privkey_filename));
}
if (!file_exists($pubkey_filename) && $domain['dkim_pubkey'] != '') {
$pubkey_file_handler = fopen($pubkey_filename, "w");
fwrite($pubkey_file_handler, $domain['dkim_pubkey']);
fclose($pubkey_file_handler);
FileDir::safe_exec("chmod 0644 " . escapeshellarg($pubkey_filename));
}
$dkimdomains .= $domain['domain'] . "\n";
$dkimkeys .= "*@" . $domain['domain'] . ":" . $domain['domain'] . ":" . $privkey_filename . "\n";
}
$dkimdomains_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/' . Settings::Get('dkim.dkim_domains'));
$dkimdomains_file_handler = fopen($dkimdomains_filename, "w");
fwrite($dkimdomains_file_handler, $dkimdomains);
fclose($dkimdomains_file_handler);
$dkimkeys_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/' . Settings::Get('dkim.dkim_dkimkeys'));
$dkimkeys_file_handler = fopen($dkimkeys_filename, "w");
fwrite($dkimkeys_file_handler, $dkimkeys);
fclose($dkimkeys_file_handler);
FileDir::safe_exec(escapeshellcmd(Settings::Get('dkim.dkimrestart_command')));
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Dkim-milter reloaded');
}
}
protected function getDomainList()
{
$result_domains_stmt = Database::query("

View File

@@ -441,7 +441,7 @@ class Apache extends HttpConfigBase
if (!empty(Settings::Get('system.dhparams_file'))) {
$dhparams = FileDir::makeCorrectFile(Settings::Get('system.dhparams_file'));
if (!file_exists($dhparams)) {
file_put_contents($dhparams, self::FFDHE4096);
FileDir::safe_exec('openssl dhparam -out ' . escapeshellarg($dhparams) . ' 4096');
}
$this->virtualhosts_data[$vhosts_filename] .= ' SSLOpenSSLConfCmd DHParameters "' . $dhparams . '"' . "\n";
}
@@ -754,7 +754,7 @@ class Apache extends HttpConfigBase
if (!empty(Settings::Get('system.dhparams_file'))) {
$dhparams = FileDir::makeCorrectFile(Settings::Get('system.dhparams_file'));
if (!file_exists($dhparams)) {
file_put_contents($dhparams, self::FFDHE4096);
FileDir::safe_exec('openssl dhparam -out ' . escapeshellarg($dhparams) . ' 4096');
}
$vhost_content .= ' SSLOpenSSLConfCmd DHParameters "' . $dhparams . '"' . "\n";
}

View File

@@ -45,26 +45,6 @@ use PDO;
class HttpConfigBase
{
/**
* Pre-defined DHE groups to use as fallback if dhparams_file
* is given, but non-existent, see also https://github.com/froxlor/Froxlor/issues/1270
*/
const FFDHE4096 = <<<EOC
-----BEGIN DH PARAMETERS-----
MIICCAKCAgEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e
8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx
iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K
zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eZV9q//////////8CAQI=
-----END DH PARAMETERS-----
EOC;
public function init()
{
// if Let's Encrypt is activated, run it before regeneration of webserver configfiles

View File

@@ -321,12 +321,9 @@ EOC;
WHERE
dom.`customerid` = cust.`customerid`
AND cust.deactivated = 0
AND dom.deactivated = 0
AND dom.`ssl_enabled` = 1
AND dom.`letsencrypt` = 1
AND dom.`aliasdomain` IS NULL
AND dom.`iswildcarddomain` = 0
AND dom.`email_only` = 0
AND domssl.`validtodate` IS NULL
");
$customer_ssl = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
@@ -385,12 +382,9 @@ EOC;
WHERE
dom.`customerid` = cust.`customerid`
AND cust.deactivated = 0
AND dom.deactivated = 0
AND dom.`ssl_enabled` = 1
AND dom.`letsencrypt` = 1
AND dom.`aliasdomain` IS NULL
AND dom.`iswildcarddomain` = 0
AND dom.`email_only` = 0
");
$renew_certs = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
if ($renew_certs) {
@@ -524,7 +518,7 @@ EOC;
self::validateDns($domains, $certrow['domainid'], $cronlog);
self::runAcmeSh($certrow, $domains, $cronlog, $do_force, $certrow['domainid'] == 0);
self::runAcmeSh($certrow, $domains, $cronlog, $do_force);
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $certrow['domain'] . " due to an enabled ssl_redirect");
// we need another reconfigure in order to get the certificate
@@ -574,7 +568,7 @@ EOC;
}
}
private static function runAcmeSh(array $certrow, array $domains, &$cronlog = null, bool $force = false, bool $renew_hook = false)
private static function runAcmeSh(array $certrow, array $domains, &$cronlog = null, $force = false)
{
if (!empty($domains)) {
$acmesh_cmd = self::getAcmeSh() . " --server " . self::$apiserver . " --issue -d " . implode(" -d ", $domains);
@@ -595,12 +589,6 @@ EOC;
if ($force) {
$acmesh_cmd .= " --force";
}
if ($renew_hook
&& !empty(trim(Settings::Get('system.le_renew_services') ?? ""))
&& !empty(trim(Settings::Get('system.le_renew_hook') ?? ""))
) {
$acmesh_cmd .= " --renew-hook '" . Settings::Get('system.le_renew_hook') . "'";
}
if (defined('CRON_DEBUG_FLAG')) {
$acmesh_cmd .= " --debug";
}
@@ -617,67 +605,12 @@ EOC;
}
} else {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, "Successful exit-code returned - storing certificate");
$cert_stored = self::certToDb($certrow, $cronlog, $acme_result);
if ($cert_stored
&& $renew_hook
&& !empty(trim(Settings::Get('system.le_renew_services') ?? ""))
&& !empty(trim(Settings::Get('system.le_renew_hook') ?? ""))
) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, "Renew-hook is enabled - adjusting configurations");
$certificate_folder = self::getCertificateFolder(strtolower(Settings::Get('system.hostname')));
$fullchain = FileDir::makeCorrectFile($certificate_folder . '/fullchain.cer');
$keyfile = FileDir::makeCorrectFile($certificate_folder . '/' . strtolower(Settings::Get('system.hostname')) . '.key');
$ca_file = FileDir::makeCorrectFile($certificate_folder . '/ca.cer');
if (Settings::IsInList('system.le_renew_services', 'postfix')) {
// "postconf -e" for postfix
FileDir::safe_exec('postconf -e smtpd_tls_cert_file=' . escapeshellarg($fullchain));
FileDir::safe_exec('postconf -e smtpd_tls_key_file=' . escapeshellarg($keyfile));
}
if (Settings::IsInList('system.le_renew_services', 'dovecot')) {
// custom config for dovecot
$dovecot_conf = '/etc/dovecot/conf.d/99-froxlor.ssl.conf'; // @fixme setting?
$ssl_content = <<<EOSSL
# Autogenerated configuration by froxlor.
# Do not manually edit this file as it will be overwritten.
ssl = yes
ssl_cert = <{$fullchain}
ssl_key = <{$keyfile}
EOSSL;
file_put_contents($dovecot_conf, $ssl_content);
}
if (Settings::IsInList('system.le_renew_services', 'proftpd')) {
$proftpd_conf = '/etc/proftpd/tls.conf'; // @fixme setting?
$rval = false;
// ECC certificate or not?
if (strpos($certificate_folder, '_ecc') === false) {
// comment out ECC related settings
FileDir::safe_exec("sed -i.bak 's|^TLSECCertificateFile|# TLSECCertificateFile|' " . escapeshellarg($proftpd_conf), $rval, ['|', '?']);
FileDir::safe_exec("sed -i.bak 's|^TLSECCertificateKeyFile|# TLSECCertificateKeyFile|' " . escapeshellarg($proftpd_conf), $rval, ['|', '?']);
// add RSA directives
FileDir::safe_exec("sed -i.bak 's|^#\?\s\?TLSRSACertificateFile.*|TLSRSACertificateFile " . $fullchain . "|' " . escapeshellarg($proftpd_conf), $rval, ['|', '?']);
FileDir::safe_exec("sed -i.bak 's|^#\?\s\?TLSRSACertificateKeyFile.*|TLSRSACertificateKeyFile " . $keyfile . "|' " . escapeshellarg($proftpd_conf), $rval, ['|', '?']);
} else {
// comment out RSA related settings
FileDir::safe_exec("sed -i.bak 's|^TLSRSACertificateFile|# TLSRSACertificateFile|' " . escapeshellarg($proftpd_conf), $rval, ['|', '?']);
FileDir::safe_exec("sed -i.bak 's|^TLSRSACertificateKeyFile|# TLSRSACertificateKeyFile|' " . escapeshellarg($proftpd_conf), $rval, ['|', '?']);
// add ECC directives
FileDir::safe_exec("sed -i.bak 's|^#\?\s\?TLSECCertificateFile.*|TLSECCertificateFile " . $fullchain . "|' " . escapeshellarg($proftpd_conf), $rval, ['|', '?']);
FileDir::safe_exec("sed -i.bak 's|^#\?\s\?TLSECCertificateKeyFile.*|TLSECCertificateKeyFile " . $keyfile . "|' " . escapeshellarg($proftpd_conf), $rval, ['|', '?']);
}
FileDir::safe_exec("sed -i.bak 's|^#\?\s\?TLSCACertificateFile.*|TLSCACertificateFile " . $ca_file . "|' " . escapeshellarg($proftpd_conf), $rval, ['|', '?']);
}
// reload the services
FileDir::safe_exec(Settings::Get('system.le_renew_hook'));
}
self::certToDb($certrow, $cronlog, $acme_result);
}
}
}
private static function certToDb($certrow, &$cronlog, $acme_result): bool
private static function certToDb($certrow, &$cronlog, $acme_result)
{
$return = [];
self::readCertificateToVar(strtolower($certrow['domain']), $return, $cronlog);
@@ -708,14 +641,12 @@ EOSSL;
}
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Updated Let's Encrypt certificate for " . $certrow['domain']);
return true;
} 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(FroxlorLogger::CRON_ACTION, LOG_ERR, "Could not get Let's Encrypt certificate for " . $certrow['domain'] . ":\n" . implode("\n", $acme_result));
}
return false;
}
/**

View File

@@ -273,7 +273,7 @@ class Lighttpd extends HttpConfigBase
if (!empty(Settings::Get('system.dhparams_file'))) {
$dhparams = FileDir::makeCorrectFile(Settings::Get('system.dhparams_file'));
if (!file_exists($dhparams)) {
file_put_contents($dhparams, self::FFDHE4096);
FileDir::safe_exec('openssl dhparam -out ' . escapeshellarg($dhparams) . ' 4096');
}
$this->lighttpd_data[$vhost_filename] .= 'ssl.dh-file = "' . $dhparams . '"' . "\n";
$this->lighttpd_data[$vhost_filename] .= 'ssl.ec-curve = "secp384r1"' . "\n";
@@ -756,7 +756,7 @@ class Lighttpd extends HttpConfigBase
if (!empty(Settings::Get('system.dhparams_file'))) {
$dhparams = FileDir::makeCorrectFile(Settings::Get('system.dhparams_file'));
if (!file_exists($dhparams)) {
file_put_contents($dhparams, self::FFDHE4096);
FileDir::safe_exec('openssl dhparam -out ' . escapeshellarg($dhparams) . ' 4096');
}
$ssl_settings .= 'ssl.dh-file = "' . $dhparams . '"' . "\n";
$ssl_settings .= 'ssl.ec-curve = "secp384r1"' . "\n";

View File

@@ -46,9 +46,10 @@ class Nginx extends HttpConfigBase
// protected
protected $needed_htpasswds = [];
protected $http2_on_directive = false;
protected $auth_backend_loaded = false;
protected $htpasswds_data = [];
protected $known_htpasswdsfilenames = [];
protected $mod_accesslog_loaded = '0';
protected $vhost_root_autoindex = false;
/**
@@ -59,18 +60,6 @@ class Nginx extends HttpConfigBase
*/
private $deactivated = false;
public function __construct()
{
$nores = false;
$res = FileDir::safe_exec('nginx -v 2>&1', $nores, ['>', '&']);
$ver_str = array_shift($res);
$cNginxVer = substr($ver_str, strrpos($ver_str, "/") + 1);
if (version_compare($cNginxVer, '1.25.1', '>=')) {
// at least 1.25.1
$this->http2_on_directive = true;
}
}
public function createVirtualHosts()
{
return;
@@ -173,10 +162,8 @@ class Nginx extends HttpConfigBase
/**
* this HAS to be set for the default host in nginx or else no vhost will work
*/
$this->nginx_data[$vhost_filename] .= "\t" . 'listen ' . $ip . ':' . $port . ' default_server' . ($ssl_vhost == true ? ' ssl' : '') . ($http2 && !$this->http2_on_directive ? ' http2' : '') . ';' . "\n";
if ($http2 && $this->http2_on_directive) {
$this->nginx_data[$vhost_filename] .= "\t" . 'http2 on;' . "\n";
}
$this->nginx_data[$vhost_filename] .= "\t" . 'listen ' . $ip . ':' . $port . ' default_server' . ($ssl_vhost == true ? ' ssl' : '') . ($http2 == true ? ' http2' : '') . ';' . "\n";
$this->nginx_data[$vhost_filename] .= "\t" . '# Froxlor default vhost' . "\n";
$aliases = "";
@@ -399,7 +386,7 @@ class Nginx extends HttpConfigBase
if (!empty(Settings::Get('system.dhparams_file'))) {
$dhparams = FileDir::makeCorrectFile(Settings::Get('system.dhparams_file'));
if (!file_exists($dhparams)) {
file_put_contents($dhparams, self::FFDHE4096);
FileDir::safe_exec('openssl dhparam -out ' . escapeshellarg($dhparams) . ' 4096');
}
$sslsettings .= "\t" . 'ssl_dhparam ' . $dhparams . ';' . "\n";
}
@@ -494,7 +481,6 @@ class Nginx extends HttpConfigBase
$vhost_content = '';
$_vhost_content = '';
$has_http2_on = false;
$query = "SELECT * FROM `" . TABLE_PANEL_IPSANDPORTS . "` `i`, `" . TABLE_DOMAINTOIP . "` `dip`
WHERE dip.id_domain = :domainid AND i.id = dip.id_ipandports ";
@@ -545,11 +531,7 @@ class Nginx extends HttpConfigBase
}
$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 && !$this->http2_on_directive ? ' http2' : '') . ';' . "\n";
if ($http2 && $this->http2_on_directive && !$has_http2_on) {
$vhost_content .= "\t" . 'http2 on;' . "\n";
$has_http2_on = true;
}
$vhost_content .= "\t" . 'listen ' . $ipport . ($ssl_vhost == true ? ' ssl' : '') . ($http2 == true ? ' http2' : '') . ';' . "\n";
}
// get all server-names

View File

@@ -1,218 +0,0 @@
<?php
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can also view it online at
* https://files.froxlor.org/misc/COPYING.txt
*
* @copyright the authors
* @author Froxlor team <team@froxlor.org>
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
namespace Froxlor\Cron\Mail;
use Exception;
use Froxlor\Database\Database;
use Froxlor\FileDir;
use Froxlor\FroxlorLogger;
use Froxlor\Settings;
class Rspamd
{
const DEFAULT_MARK_LVL = 7.0;
const DEFAULT_REJECT_LVL = 14.0;
private string $frx_settings_file = "";
protected FroxlorLogger $logger;
public function __construct(FroxlorLogger $logger)
{
$this->logger = $logger;
}
/**
* @throws Exception
*/
public function writeConfigs()
{
// tell the world what we are doing
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Task9 started - Rebuilding antispam configuration');
// get all email addresses
$antispam_stmt = Database::prepare("
SELECT email, spam_tag_level, spam_kill_level, bypass_spam, policy_greylist, iscatchall
FROM `" . TABLE_MAIL_VIRTUAL . "`
ORDER BY email
");
Database::pexecute($antispam_stmt);
$this->frx_settings_file = "#\n# Automatically generated file by froxlor. DO NOT EDIT manually as it will be overwritten!\n# Generated: " . date('d.m.Y H:i') . "\n#\n\n";
while ($email = $antispam_stmt->fetch(\PDO::FETCH_ASSOC)) {
$this->generateEmailAddrConfig($email);
}
$antispam_cfg_file = FileDir::makeCorrectFile(Settings::Get('antispam.config_file'));
file_put_contents($antispam_cfg_file, $this->frx_settings_file);
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, $antispam_cfg_file . ' written');
$this->writeDkimConfigs();
$this->reloadDaemon();
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Task9 finished');
}
/**
* # local.d/dkim_signing.conf
* try_fallback = true;
* path = "/var/lib/rspamd/dkim/$domain.$selector.key";
* selector_map = "/etc/rspamd/dkim_selectors.map";
*
* @return void
* @throws Exception
*/
public function writeDkimConfigs()
{
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Writing DKIM key-pairs');
$dkim_selector_map = "";
$result_domains_stmt = Database::query("
SELECT `id`, `domain`, `dkim`, `dkim_id`, `dkim_pubkey`, `dkim_privkey`
FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `dkim` = '1'
ORDER BY `id` ASC
");
while ($domain = $result_domains_stmt->fetch(\PDO::FETCH_ASSOC)) {
if ($domain['dkim_privkey'] == '' || $domain['dkim_pubkey'] == '') {
$max_dkim_id_stmt = Database::query("SELECT MAX(`dkim_id`) as `max_dkim_id` FROM `" . TABLE_PANEL_DOMAINS . "`");
$max_dkim_id = $max_dkim_id_stmt->fetch(\PDO::FETCH_ASSOC);
$domain['dkim_id'] = (int)$max_dkim_id['max_dkim_id'] + 1;
$privkey_filename = FileDir::makeCorrectFile('/var/lib/rspamd/dkim/' . $domain['domain'] . '.dkim' . $domain['dkim_id'] . '.key');
$pubkey_filename = FileDir::makeCorrectFile('/var/lib/rspamd/dkim/' . $domain['domain'] . '.dkim' . $domain['dkim_id'] . '.txt');
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Generating DKIM keys for "' . $domain['domain'] . '"');
$rsret = [];
FileDir::safe_exec(
'rspamadm dkim_keygen -d ' . escapeshellarg($domain['domain']) . ' -k ' . $privkey_filename . ' -s dkim' . $domain['dkim_id'] . ' -b ' . Settings::Get('antispam.dkim_keylength') . ' -o plain > ' . escapeshellarg($pubkey_filename),
$rsret,
['>']
);
if (!file_exists($privkey_filename) || !file_exists($pubkey_filename)) {
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'DKIM Keypair for domain "' . $domain['domain'] . '" was not generated successfully.');
continue;
}
$domain['dkim_privkey'] = file_get_contents($privkey_filename);
FileDir::safe_exec("chmod 0640 " . escapeshellarg($privkey_filename));
FileDir::safe_exec("chown _rspamd:_rspamd " . escapeshellarg($privkey_filename));
$domain['dkim_pubkey'] = file_get_contents($pubkey_filename);
FileDir::safe_exec("chmod 0664 " . escapeshellarg($pubkey_filename));
FileDir::safe_exec("chown _rspamd:_rspamd " . escapeshellarg($pubkey_filename));
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
`dkim_id` = :dkimid,
`dkim_privkey` = :privkey,
`dkim_pubkey` = :pubkey
WHERE `id` = :id
");
$upd_data = [
'dkimid' => $domain['dkim_id'],
'privkey' => $domain['dkim_privkey'],
'pubkey' => $domain['dkim_pubkey'],
'id' => $domain['id']
];
Database::pexecute($upd_stmt, $upd_data);
} else {
$privkey_filename = FileDir::makeCorrectFile('/var/lib/rspamd/dkim/' . $domain['domain'] . '.dkim' . $domain['dkim_id'] . '.key');
$pubkey_filename = FileDir::makeCorrectFile('/var/lib/rspamd/dkim/' . $domain['domain'] . '.dkim' . $domain['dkim_id'] . '.txt');
}
if (!file_exists($privkey_filename) && $domain['dkim_privkey'] != '') {
file_put_contents($privkey_filename, $domain['dkim_privkey']);
FileDir::safe_exec("chmod 0640 " . escapeshellarg($privkey_filename));
FileDir::safe_exec("chown _rspamd:_rspamd " . escapeshellarg($privkey_filename));
}
if (!file_exists($pubkey_filename) && $domain['dkim_pubkey'] != '') {
file_put_contents($pubkey_filename, $domain['dkim_pubkey']);
FileDir::safe_exec("chmod 0644 " . escapeshellarg($pubkey_filename));
FileDir::safe_exec("chown _rspamd:_rspamd " . escapeshellarg($pubkey_filename));
}
$dkim_selector_map .= $domain['domain'] . " dkim" . $domain['dkim_id'] . "\n";
}
$dkim_selector_file = FileDir::makeCorrectFile('/etc/rspamd/dkim_selectors.map');
file_put_contents($dkim_selector_file, $dkim_selector_map);
}
private function generateEmailAddrConfig(array $email): void
{
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Generating antispam config for ' . $email['email']);
$email['spam_tag_level'] = floatval($email['spam_tag_level']);
$email['spam_kill_level'] = $email['spam_kill_level'] == -1 ? "null" : floatval($email['spam_kill_level']);
$email_id = md5($email['email']);
$this->frx_settings_file .= '# Email: ' . $email['email'] . "\n";
foreach (['rcpt', 'from'] as $type) {
$this->frx_settings_file .= 'frx_' . $email_id . '_' . $type . ' {' . "\n";
$this->frx_settings_file .= ' id = "frx_' . $email_id . '_' . $type . '";' . "\n";
if ($email['iscatchall']) {
$this->frx_settings_file .= ' priority = low;' . "\n";
$this->frx_settings_file .= ' ' . $type . ' = "' . substr($email['email'], strpos($email['email'], '@')) . '";' . "\n";
} else {
$this->frx_settings_file .= ' priority = medium;' . "\n";
$this->frx_settings_file .= ' ' . $type . ' = "' . $email['email'] . '";' . "\n";
}
if ((int)$email['bypass_spam'] == 1) {
$this->frx_settings_file .= ' want_spam = yes;' . "\n";
} else {
$this->frx_settings_file .= ' apply {' . "\n";
$this->frx_settings_file .= ' actions {' . "\n";
$this->frx_settings_file .= ' "add header" = ' . $email['spam_tag_level'] . ';' . "\n";
if ((int)$email['rewrite_subject'] == 1) {
$this->frx_settings_file .= ' rewrite_subject = ' . ($email['spam_tag_level'] + 0.01) . ';' . "\n";
}
$this->frx_settings_file .= ' reject = ' . $email['spam_kill_level'] . ';' . "\n";
if ($type == 'rcpt' && (int)$email['policy_greylist'] == 0) {
$this->frx_settings_file .= ' greylist = null;' . "\n";
}
$this->frx_settings_file .= ' }' . "\n";
$this->frx_settings_file .= ' }' . "\n";
if ($type == 'rcpt' && (int)$email['policy_greylist'] == 0) {
$this->frx_settings_file .= ' symbols [ "DONT_GREYLIST" ]' . "\n";
}
}
$this->frx_settings_file .= '}' . "\n";
}
$this->frx_settings_file .= "\n";
}
public function reloadDaemon()
{
// reload DNS daemon
$cmd = Settings::Get('antispam.reload_command');
$cmdStatus = 1;
FileDir::safe_exec(escapeshellcmd($cmd), $cmdStatus);
if ($cmdStatus === 0) {
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Antispam daemon reloaded');
} else {
$this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'Error while running `' . $cmd . '`: exit code (' . $cmdStatus . ') - please check your system logs');
}
}
}

View File

@@ -25,11 +25,9 @@
namespace Froxlor\Cron\System;
use Exception;
use Froxlor\Cron\FroxlorCron;
use Froxlor\Cron\Http\ConfigIO;
use Froxlor\Cron\Http\HttpConfigBase;
use Froxlor\Cron\Mail\Rspamd;
use Froxlor\Cron\TaskId;
use Froxlor\Database\Database;
use Froxlor\Dns\PowerDNS;
@@ -42,9 +40,6 @@ use PDO;
class TasksCron extends FroxlorCron
{
/**
* @throws Exception
*/
public static function run()
{
/**
@@ -103,11 +98,6 @@ class TasksCron extends FroxlorCron
* refs #293
*/
self::deleteFtpData($row);
} elseif ($row['type'] == TaskId::REBUILD_RSPAMD && (int)Settings::Get('antispam.activated') != 0) {
/**
* TYPE=9 Rebuild antispam config
*/
self::rebuildAntiSpamConfigs();
} elseif ($row['type'] == TaskId::CREATE_QUOTA && (int)Settings::Get('system.diskquota_enabled') != 0) {
/**
* TYPE=10 Set the filesystem - quota
@@ -276,7 +266,13 @@ class TasksCron extends FroxlorCron
private static function rebuildDnsConfigs()
{
$dnssrv = '\\Froxlor\\Cron\\Dns\\' . Settings::Get('system.dns_server');
$nameserver = new $dnssrv(FroxlorLogger::getInstanceOf());
if (Settings::Get('dkim.use_dkim') == '1') {
$nameserver->writeDKIMconfigs();
}
$nameserver->writeConfigs();
}
@@ -348,16 +344,24 @@ class TasksCron extends FroxlorCron
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'TasksCron: Task7 started - deleting customer e-mail data');
if (is_array($row['data'])) {
if (isset($row['data']['loginname']) && isset($row['data']['emailpath'])) {
if (isset($row['data']['loginname']) && isset($row['data']['email'])) {
// remove specific maildir
$email_full = $row['data']['emailpath'];
$email_full = $row['data']['email'];
if (empty($email_full)) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'FATAL: Task7 asks to delete a email account but emailpath field is empty!');
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'FATAL: Task7 asks to delete a email account but email field is empty!');
}
$email_user = substr($email_full, 0, strrpos($email_full, "@"));
$email_domain = substr($email_full, strrpos($email_full, "@") + 1);
$maildirname = trim(Settings::Get('system.vmail_maildirname'));
// Add trailing slash to Maildir if needed
$maildirpath = $maildirname;
if (!empty($maildirname) and substr($maildirname, -1) != "/") {
$maildirpath .= "/";
}
$maildir = FileDir::makeCorrectDir($email_full);
$maildir = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $email_domain . '/' . $email_user);
if ($maildir != '/' && !empty($maildir) && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) {
if ($maildir != '/' && !empty($maildir) && !empty($email_full) && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && is_dir(FileDir::makeCorrectDir($maildir . '/' . $maildirpath)) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir));
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
$return = false;
@@ -369,6 +373,23 @@ class TasksCron extends FroxlorCron
'~',
'?'
]);
} else {
// backward-compatibility for old folder-structure
$maildir_old = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $row['data']['email']);
if ($maildir_old != '/' && !empty($maildir_old) && $maildir_old != Settings::Get('system.vmail_homedir') && substr($maildir_old, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir_old) && fileowner($maildir_old) == Settings::Get('system.vmail_uid') && filegroup($maildir_old) == Settings::Get('system.vmail_gid')) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir_old));
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
$return = false;
FileDir::safe_exec('rm -rf ' . escapeshellarg($maildir_old), $return, [
'|',
'&',
'`',
'$',
'~',
'?'
]);
}
}
}
}
@@ -427,13 +448,4 @@ class TasksCron extends FroxlorCron
}
}
}
/**
* @throws Exception
*/
private static function rebuildAntiSpamConfigs()
{
$antispam = new Rspamd(FroxlorLogger::getInstanceOf());
$antispam->writeConfigs();
}
}

View File

@@ -66,12 +66,6 @@ final class TaskId
*/
const DELETE_FTP_DATA = 8;
/**
* TYPE=9 MEANS THAT SOMETHING ANTISPAM RELATED HAS CHANGED.
* REBUILD froxlor_settings.conf IF ANTISPAM IS ENABLED
*/
const REBUILD_RSPAMD = 9;
/**
* TYPE=10 Set the filesystem - quota
*/

View File

@@ -70,7 +70,7 @@ class ReportsCron extends FroxlorCron
) as `traffic_used`
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c`
LEFT JOIN `" . TABLE_PANEL_ADMINS . "` AS `a`
ON `a`.`adminid` = `c`.`adminid` WHERE `c`.`reportsent` & 1 = 0
ON `a`.`adminid` = `c`.`adminid` WHERE `c`.`reportsent` <> '1'
");
$result_data = [
@@ -79,11 +79,6 @@ class ReportsCron extends FroxlorCron
];
Database::pexecute($result_stmt, $result_data);
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `reportsent` = `reportsent` + 1
WHERE `customerid` = :customerid
");
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$row['traffic'] *= 1024;
$row['traffic_used'] *= 1024;
@@ -153,6 +148,10 @@ class ReportsCron extends FroxlorCron
}
$mail->ClearAddresses();
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `reportsent` = '1'
WHERE `customerid` = :customerid
");
Database::pexecute($upd_stmt, [
'customerid' => $row['customerid']
]);
@@ -166,7 +165,7 @@ class ReportsCron extends FroxlorCron
FROM `" . TABLE_PANEL_TRAFFIC_ADMINS . "` `t`
WHERE `t`.`adminid` = `a`.`adminid` AND `t`.`year` = :year AND `t`.`month` = :month
) as `traffic_used_total`
FROM `" . TABLE_PANEL_ADMINS . "` `a` WHERE `a`.`reportsent` & 1 = 0
FROM `" . TABLE_PANEL_ADMINS . "` `a` WHERE `a`.`reportsent` = '0'
");
$result_data = [
@@ -175,11 +174,6 @@ class ReportsCron extends FroxlorCron
];
Database::pexecute($result_stmt, $result_data);
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_ADMINS . "` SET `reportsent` = `reportsent` + 1
WHERE `adminid` = :adminid
");
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$row['traffic'] *= 1024;
$row['traffic_used_total'] *= 1024;
@@ -217,7 +211,7 @@ class ReportsCron extends FroxlorCron
$_mailerror = false;
$mailerr_msg = "";
try {
$mail->SetFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname'));
$mail->SetFrom($row['email'], $row['name']);
$mail->Subject = $mail_subject;
$mail->AltBody = $mail_body;
$mail->MsgHTML(nl2br($mail_body));
@@ -237,6 +231,10 @@ class ReportsCron extends FroxlorCron
}
$mail->ClearAddresses();
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_ADMINS . "` SET `reportsent` = '1'
WHERE `adminid` = :adminid
");
Database::pexecute($upd_stmt, [
'adminid' => $row['adminid']
]);
@@ -299,7 +297,7 @@ class ReportsCron extends FroxlorCron
$_mailerror = false;
$mailerr_msg = "";
try {
$mail->SetFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname'));
$mail->SetFrom($row['email'], $row['name']);
$mail->Subject = $mail_subject;
$mail->Body = $mail_body;
$mail->MsgHTML(nl2br($mail_body));
@@ -346,16 +344,11 @@ class ReportsCron extends FroxlorCron
FROM `" . TABLE_PANEL_CUSTOMERS . "` AS `c`
LEFT JOIN `" . TABLE_PANEL_ADMINS . "` AS `a`
ON `a`.`adminid` = `c`.`adminid`
WHERE `c`.`diskspace` > '0' AND `c`.`reportsent` & 2 = 0
WHERE `c`.`diskspace` > '0' AND `c`.`reportsent` <> '2'
");
$mail = new Mailer(true);
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `reportsent` = `reportsent` + 2
WHERE `customerid` = :customerid
");
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$row['diskspace'] *= 1024;
$row['diskspace_used'] *= 1024;
@@ -425,6 +418,10 @@ class ReportsCron extends FroxlorCron
}
$mail->ClearAddresses();
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET `reportsent` = '2'
WHERE `customerid` = :customerid
");
Database::pexecute($upd_stmt, [
'customerid' => $row['customerid']
]);
@@ -435,12 +432,7 @@ class ReportsCron extends FroxlorCron
* report about diskusage for admins/reseller
*/
$result_stmt = Database::query("
SELECT `a`.* FROM `" . TABLE_PANEL_ADMINS . "` `a` WHERE `a`.`reportsent` & 2 = 0
");
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_ADMINS . "` SET `reportsent` = `reportsent` + 2
WHERE `adminid` = :adminid
SELECT `a`.* FROM `" . TABLE_PANEL_ADMINS . "` `a` WHERE `a`.`reportsent` <> '2'
");
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
@@ -480,7 +472,7 @@ class ReportsCron extends FroxlorCron
$_mailerror = false;
$mailerr_msg = "";
try {
$mail->SetFrom(Settings::Get('panel.adminmail'), Settings::Get('panel.adminmail_defname'));
$mail->SetFrom($row['email'], $row['name']);
$mail->Subject = $mail_subject;
$mail->AltBody = $mail_body;
$mail->MsgHTML(nl2br($mail_body));
@@ -500,6 +492,10 @@ class ReportsCron extends FroxlorCron
}
$mail->ClearAddresses();
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_ADMINS . "` SET `reportsent` = '2'
WHERE `adminid` = :adminid
");
Database::pexecute($upd_stmt, [
'adminid' => $row['adminid']
]);

View File

@@ -122,7 +122,7 @@ class TrafficCron extends FroxlorCron
if ($mysql_usage_row) {
$mysqlusage_all[$row_database['customerid']] += floatval($mysql_usage_row['customerusage']);
} else {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, "Cannot get usage for database " . $row_database['databasename'] . ".");
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Cannot get usage for database " . $row_database['databasename'] . ".");
}
} else {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Seems like the database " . $row_database['databasename'] . " had been removed manually.");

View File

@@ -46,7 +46,7 @@ class CurrentUser
*/
public static function hasSession(): bool
{
return !empty($_SESSION) && !empty($_SESSION['userinfo']);
return !empty($_SESSION) && isset($_SESSION['userinfo']) && !empty($_SESSION['userinfo']);
}
/**

View File

@@ -32,7 +32,7 @@ class Customer
{
/**
* Get value of a specific field from a given customer
* Get value of a a specific field from a given customer
*
* @param int $customerid
* @param string $varname

View File

@@ -25,7 +25,6 @@
namespace Froxlor\Database;
use Exception;
use Froxlor\Database\Manager\DbManagerMySQL;
use Froxlor\Froxlor;
use Froxlor\FroxlorLogger;
@@ -84,7 +83,7 @@ class DbManager
* @param array $mysql_access_host_array
*
* @return void
* @throws Exception
* @throws \Exception
*/
public static function correctMysqlUsers(array $mysql_access_host_array)
{
@@ -111,7 +110,7 @@ class DbManager
$users = $dbm->getManager()->getAllSqlUsers(false);
foreach ($databases[$dbserver['dbserver']] as $username) {
if (isset($users[$username]['hosts']) && is_array($users[$username]['hosts'])) {
if (isset($users[$username]) && is_array($users[$username]) && isset($users[$username]['hosts']) && is_array($users[$username]['hosts'])) {
$password = [
'password' => $users[$username]['password'],
@@ -151,7 +150,6 @@ class DbManager
* @param int $last_accnumber
*
* @return string|bool $username if successful or false of username is equal to the password
* @throws Exception
*/
public function createDatabase(string $loginname = null, string $password = null, int $dbserver = 0, int $last_accnumber = 0)
{

View File

@@ -76,14 +76,11 @@ class DbManagerMySQL
* optional, whether the password is encrypted or not, default false
* @param bool $update
* optional, whether to update the password only (not create user)
* @param bool $grant_access_prefix
* optional, whether the given user will have access to all databases starting with the username, default false
* @throws \Exception
*/
public function grantPrivilegesTo(string $username, $password, string $access_host = null, bool $p_encrypted = false, bool $update = false, bool $grant_access_prefix = false)
public function grantPrivilegesTo(string $username, $password, string $access_host = null, bool $p_encrypted = false, bool $update = false)
{
// this is required for mysql8
$pwd_plugin = 'caching_sha2_password';
$pwd_plugin = 'mysql_native_password';
if (is_array($password) && count($password) == 2) {
$pwd_plugin = $password['plugin'];
$password = $password['password'];
@@ -111,7 +108,7 @@ class DbManagerMySQL
]);
// grant privileges
$stmt = Database::prepare("
GRANT ALL ON `" . $username . ($grant_access_prefix ? '%' : '') . "`.* TO :username@:host
GRANT ALL ON `" . $username . "`.* TO :username@:host
");
Database::pexecute($stmt, [
"username" => $username,
@@ -187,23 +184,21 @@ class DbManagerMySQL
*/
public function deleteUser(string $username, string $host)
{
if ($this->userExistsOnHost($username, $host)) {
if (version_compare(Database::getAttribute(PDO::ATTR_SERVER_VERSION), '5.0.2', '<')) {
// Revoke privileges (only required for MySQL 4.1.2 - 5.0.1)
$stmt = Database::prepare("REVOKE ALL PRIVILEGES ON * . * FROM `" . $username . "`@`" . $host . "`");
Database::pexecute($stmt);
}
// as of MySQL 5.0.2 this also revokes privileges. (requires MySQL 4.1.2+)
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, [
"username" => $username,
"host" => $host
]);
if (Database::getAttribute(PDO::ATTR_SERVER_VERSION) < '5.0.2') {
// Revoke privileges (only required for MySQL 4.1.2 - 5.0.1)
$stmt = Database::prepare("REVOKE ALL PRIVILEGES ON * . * FROM `" . $username . "`@`" . $host . "`");
Database::pexecute($stmt);
}
// as of MySQL 5.0.2 this also revokes privileges. (requires MySQL 4.1.2+)
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, [
"username" => $username,
"host" => $host
]);
}
/**
@@ -224,31 +219,17 @@ class DbManagerMySQL
*
* @param string $username
* @param string $host
* @param bool $grant_access_prefix
* @throws \Exception
*/
public function enableUser(string $username, string $host, bool $grant_access_prefix = false)
public function enableUser(string $username, string $host)
{
// check whether user exists to avoid errors
if ($this->userExistsOnHost($username, $host)) {
Database::query('GRANT ALL PRIVILEGES ON `' . $username . ($grant_access_prefix ? '%' : '') . '`.* TO `' . $username . '`@`' . $host . '`');
Database::query('GRANT ALL PRIVILEGES ON `' . str_replace('_', '\_', $username) . ($grant_access_prefix ? '%' : '') . '` . * TO `' . $username . '`@`' . $host . '`');
}
}
/**
* Check whether a given username exists for the given host
*
* @param string $username
* @param string $host
* @return bool
* @throws \Exception
*/
public function userExistsOnHost(string $username, string $host): bool
{
$exist_check_stmt = Database::prepare("SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '" . $username . "' AND host = '" . $host . "')");
$exist_check = Database::pexecute_first($exist_check_stmt);
return ($exist_check && array_pop($exist_check) == '1');
if ($exist_check && array_pop($exist_check) == '1') {
Database::query('GRANT ALL PRIVILEGES ON `' . $username . '`.* TO `' . $username . '`@`' . $host . '`');
Database::query('GRANT ALL PRIVILEGES ON `' . str_replace('_', '\_', $username) . '` . * TO `' . $username . '`@`' . $host . '`');
}
}
/**
@@ -281,7 +262,7 @@ class DbManagerMySQL
if (!isset($allsqlusers[$row['User']]) || !is_array($allsqlusers[$row['User']])) {
$allsqlusers[$row['User']] = [
'password' => $row['Password'] ?? $row['authentication_string'],
'plugin' => $row['plugin'] ?? 'caching_sha2_password',
'plugin' => $row['plugin'] ?? 'mysql_native_password',
'hosts' => []
];
}

View File

@@ -54,7 +54,7 @@ class Dns
$dom_data['uid'] = $userinfo['userid'];
}
} else {
$where_clause = '`customerid` = :uid AND `email_only` = "0" AND ';
$where_clause = '`customerid` = :uid AND ';
$dom_data['uid'] = $userinfo['userid'];
}
@@ -120,8 +120,20 @@ class Dns
if ($domain['isemaildomain'] == '1') {
self::addRequiredEntry('@', 'MX', $required_entries);
if (Settings::Get('system.dns_createmailentry')) {
foreach (['imap', 'pop3', 'mail', 'smtp' ] as $record ) {
foreach (['AAAA', 'A' ] as $type ) {
foreach (
[
'imap',
'pop3',
'mail',
'smtp'
] as $record
) {
foreach (
[
'AAAA',
'A'
] as $type
) {
self::addRequiredEntry($record, $type, $required_entries);
}
}
@@ -140,9 +152,9 @@ class Dns
if (!$froxlorhostname) {
// additional required records for subdomains
$subdomains_stmt = Database::prepare("
SELECT `domain`, `iswildcarddomain`, `wwwserveralias`, `isemaildomain` FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `parentdomainid` = :domainid
");
SELECT `domain`, `iswildcarddomain`, `wwwserveralias`, `isemaildomain` FROM `" . TABLE_PANEL_DOMAINS . "`
WHERE `parentdomainid` = :domainid
");
Database::pexecute($subdomains_stmt, [
'domainid' => $domain_id
]);
@@ -151,7 +163,7 @@ class Dns
$sub_record = str_replace('.' . $domain['domain'], '', $subdomain['domain']);
// Listing domains is enough as there currently is no support for choosing
// different ips for a subdomain => use same IPs as toplevel
self::addRequiredEntry($sub_record, 'A', $required_entries);
self::addRequiredEntry($sub_record, 'A',$required_entries);
self::addRequiredEntry($sub_record, 'AAAA', $required_entries);
// Check whether to add a www.-prefix
@@ -169,11 +181,7 @@ class Dns
// check for SPF content later
self::addRequiredEntry('@SPF@.' . $sub_record, 'TXT', $required_entries);
}
if (Settings::Get('dmarc.use_dmarc') == '1') {
// check for DMARC content later
self::addRequiredEntry('@DMARC@.' . $sub_record, 'TXT', $required_entries);
}
if (Settings::Get('antispam.activated') == '1' && $domain['dkim'] == '1') {
if (Settings::Get('dkim.use_dkim') == '1') {
// check for DKIM content later
self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey.' . $sub_record, 'TXT', $required_entries);
}
@@ -210,11 +218,7 @@ class Dns
// check for SPF content later
self::addRequiredEntry('@SPF@', 'TXT', $required_entries);
}
if (Settings::Get('dmarc.use_dmarc') == '1') {
// check for DMARC content later
self::addRequiredEntry('@DMARC@', 'TXT', $required_entries);
}
if (Settings::Get('antispam.activated') == '1' && $domain['dkim'] == '1') {
if (Settings::Get('dkim.use_dkim') == '1') {
// check for DKIM content later
self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey', 'TXT', $required_entries);
}
@@ -225,64 +229,51 @@ class Dns
// now generate all records and unset the required entries we have
foreach ($dom_entries as $entry) {
if (array_key_exists($entry['type'], $required_entries)
&& array_key_exists( md5($entry['record']), $required_entries[$entry['type']])
) {
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'
) {
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'
&& (strtolower(substr($entry['content'], 0, 7)) == '"v=spf1' || strtolower(substr($entry['content'], 0, 6)) == 'v=spf1')
) {
if (Settings::Get('spf.use_spf') == '1' && $entry['type'] == 'TXT' && $entry['record'] == '@' && (strtolower(substr($entry['content'],
0, 7)) == '"v=spf1' || strtolower(substr($entry['content'], 0, 6)) == 'v=spf1')) {
// unset special spf required-entry
if ($entry['record'] == '@') {
unset($required_entries[$entry['type']][md5("@SPF@")]);
} else {
// subdomain
unset($required_entries[$entry['type']][md5("@SPF@." . $entry['record'])]);
}
}
if (Settings::Get('dmarc.use_dmarc') == '1'
&& $entry['type'] == 'TXT'
&& ($entry['record'] == '_dmarc' || substr($entry['record'], 0, 7) == '_dmarc.')
&& (strtolower(substr($entry['content'], 0, 9)) == '"v=dmarc1' || strtolower(substr($entry['content'], 0, 8)) == 'v=dmarc1')
) {
// unset special dmarc required-entry
if ($entry['record'] == '_dmarc') {
unset($required_entries[$entry['type']][md5("@DMARC@")]);
} else {
// subdomain
unset($required_entries[$entry['type']][md5("@DMARC@" . substr($entry['record'], 6))]);
}
unset($required_entries[$entry['type']][md5("@SPF@")]);
}
if (empty($primary_ns) && $entry['record'] == '@' && $entry['type'] == 'NS') {
// use the first NS entry pertaining to the current domain as primary ns
$primary_ns = $entry['content'];
}
// check for CNAME on @, www- or wildcard-Alias and remove A/AAAA record accordingly
foreach (['@', 'www', '*'] as $crecord) {
if ($entry['type'] == 'CNAME'
&& $entry['record'] == '@'
&& (array_key_exists(md5($crecord), $required_entries['A']) || array_key_exists(md5($crecord), $required_entries['AAAA']))
) {
foreach (
[
'@',
'www',
'*'
] as $crecord
) {
if ($entry['type'] == 'CNAME' && $entry['record'] == '@' && (array_key_exists(md5($crecord),
$required_entries['A']) || array_key_exists(md5($crecord), $required_entries['AAAA']))) {
unset($required_entries['A'][md5($crecord)]);
unset($required_entries['AAAA'][md5($crecord)]);
}
}
// also allow overriding of auto-generated values (imap,pop3,mail,smtp) if enabled in the settings
if (Settings::Get('system.dns_createmailentry')) {
foreach (['imap', 'pop3', 'mail', 'smtp'] as $crecord) {
if ($entry['type'] == 'CNAME'
&& $entry['record'] == $crecord
&& (array_key_exists(md5($crecord), $required_entries['A']) || array_key_exists(md5($crecord), $required_entries['AAAA']))
) {
foreach (
[
'imap',
'pop3',
'mail',
'smtp'
] as $crecord
) {
if ($entry['type'] == 'CNAME' && $entry['record'] == $crecord && (array_key_exists(md5($crecord),
$required_entries['A']) || array_key_exists(md5($crecord),
$required_entries['AAAA']))) {
unset($required_entries['A'][md5($crecord)]);
unset($required_entries['AAAA'][md5($crecord)]);
}
@@ -319,7 +310,8 @@ class Dns
foreach ($records as $record) {
if ($type == 'A' && filter_var($ip['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
$zonerecords[] = new DnsEntry($record, 'A', $ip['ip']);
} elseif ($type == 'AAAA' && filter_var($ip['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) !== false) {
} elseif ($type == 'AAAA' && filter_var($ip['ip'], FILTER_VALIDATE_IP,
FILTER_FLAG_IPV6) !== false) {
$zonerecords[] = new DnsEntry($record, 'AAAA', $ip['ip']);
}
}
@@ -384,7 +376,9 @@ class Dns
// TXT (SPF and DKIM)
if (array_key_exists("TXT", $required_entries)) {
$dkim_entries = self::generateDkimEntries($domain);
if (Settings::Get('dkim.use_dkim') == '1') {
$dkim_entries = self::generateDkimEntries($domain);
}
foreach ($required_entries as $type => $records) {
if ($type == 'TXT') {
@@ -398,15 +392,6 @@ class Dns
$txt_content = Settings::Get('spf.spf_entry');
$sub_record = substr($record, 6);
$zonerecords[] = new DnsEntry($sub_record, 'TXT', self::encloseTXTContent($txt_content));
} elseif ($record == '@DMARC@') {
// dmarc for main-domain
$txt_content = Settings::Get('dmarc.dmarc_entry');
$zonerecords[] = new DnsEntry('_dmarc', 'TXT', self::encloseTXTContent($txt_content));
} elseif (strlen($record) > 8 && substr($record, 0, 8) == '@DMARC@.') {
// dmarc for subdomain
$txt_content = Settings::Get('dmarc.dmarc_entry');
$sub_record = substr($record, 8);
$zonerecords[] = new DnsEntry('_dmarc.' . $sub_record, 'TXT', self::encloseTXTContent($txt_content));
} elseif (!empty($dkim_entries)) {
// DKIM entries
$dkim_record = 'dkim' . $domain['dkim_id'] . '._domainkey';
@@ -418,7 +403,7 @@ class Dns
$multiline = true;
}
$zonerecords[] = new DnsEntry($record, 'TXT', self::encloseTXTContent($dkim_entries[0], $multiline));
} elseif (strlen($record) > strlen($dkim_record) && substr($record, 0, strlen($dkim_record) + 1) == $dkim_record . '.') {
} elseif (strlen($record) > strlen($dkim_record) && substr($record, 0, strlen($dkim_record)+1) == $dkim_record . '.') {
// dkim for subdomain-domain
// check for multiline entry
$multiline = false;
@@ -486,7 +471,8 @@ class Dns
if (!$isMainButSubTo) {
$date = date('Ymd');
$domain['bindserial'] = (preg_match('/^' . $date . '/', $domain['bindserial']) ? $domain['bindserial'] + 1 : $date . '00');
$domain['bindserial'] = (preg_match('/^' . $date . '/',
$domain['bindserial']) ? $domain['bindserial'] + 1 : $date . '00');
if (!$froxlorhostname) {
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
@@ -513,12 +499,8 @@ class Dns
array_unshift($zonerecords, $soa_record);
}
$zone = new DnsZone(
(int)Settings::Get('system.defaultttl'),
$domain['domain'],
$domain['bindserial'],
$zonerecords
);
$zone = new DnsZone((int)Settings::Get('system.defaultttl'), $domain['domain'], $domain['bindserial'],
$zonerecords);
return $zone;
}
@@ -545,11 +527,43 @@ class Dns
{
$zone_dkim = [];
if (Settings::Get('antispam.activated') == '1' && $domain['dkim'] == '1' && $domain['dkim_pubkey'] != '') {
if (Settings::Get('dkim.use_dkim') == '1' && $domain['dkim'] == '1' && $domain['dkim_pubkey'] != '') {
// start
$dkim_txt = 'v=DKIM1;';
// algorithm
$algorithm = explode(',', Settings::Get('dkim.dkim_algorithm'));
$alg = '';
foreach ($algorithm as $a) {
if ($a == 'all') {
break;
} else {
$alg .= $a . ':';
}
}
if ($alg != '') {
$alg = substr($alg, 0, -1);
$dkim_txt .= 'h=' . $alg . ';';
}
// notes
if (trim(Settings::Get('dkim.dkim_notes') != '')) {
$dkim_txt .= 'n=' . trim(Settings::Get('dkim.dkim_notes')) . ';';
}
// key
$dkim_txt .= 'k=rsa;p=' . trim($domain['dkim_pubkey']) . ';';
$dkim_txt .= 'k=rsa;p=' . trim(preg_replace('/-----BEGIN PUBLIC KEY-----(.+)-----END PUBLIC KEY-----/s',
'$1', str_replace("\n", '', $domain['dkim_pubkey']))) . ';';
// service-type
if (Settings::Get('dkim.dkim_servicetype') == '1') {
$dkim_txt .= 's=email;';
}
// end-part
$dkim_txt .= 't=s';
// dkim-entry
$zone_dkim[] = $dkim_txt;
}

View File

@@ -1,77 +0,0 @@
<?php
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can also view it online at
* https://files.froxlor.org/misc/COPYING.txt
*
* @copyright the authors
* @author Froxlor team <team@froxlor.org>
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
namespace Froxlor;
use Exception;
/**
* Class to manage the current user / session
*/
class ErrorBag
{
/**
* returns whether there are errors stored
*
* @return bool
*/
public static function hasErrors(): bool
{
return !empty($_SESSION) && !empty($_SESSION['_errors']);
}
/**
* add error
*
* @param string $data
*
* @return void
*/
public static function addError(string $data): void
{
if (!isset($_SESSION['_errors']) || !is_array($_SESSION['_errors'])) {
$_SESSION['_errors'] = [];
}
$_SESSION['_errors'][] = $data;
}
/**
* Return errors and clear session
*
* @return array
* @throws Exception
*/
public static function getErrors(): array
{
$errors = $_SESSION['_errors'] ?? [];
unset($_SESSION['_errors']);
if (Settings::Config('display_php_errors')) {
return $errors;
}
return [];
}
}

View File

@@ -31,15 +31,15 @@ final class Froxlor
{
// Main version variable
const VERSION = '2.2.2';
const VERSION = '2.1.9';
// Database version (YYYYMMDDC where C is a daily counter)
const DBVERSION = '202409280';
const DBVERSION = '202312120';
// Distribution branding-tag (used for Debian etc.)
const BRANDING = '';
const DOCS_URL = 'https://docs.froxlor.org';
const DOCS_URL = 'https://docs.froxlor.org/v2.1/';
/**
* return path to where froxlor is installed, e.g.
@@ -52,14 +52,6 @@ final class Froxlor
return dirname(__DIR__, 2) . '/';
}
public static function getDocsUrl(): string
{
if (preg_match('/(.+)-(dev|beta|rc)\d+$/', self::VERSION)) {
return self::DOCS_URL . '/dev/';
}
return self::DOCS_URL . '/v' . self::getShortVersion() . '/';
}
/**
* return basic version
*
@@ -70,16 +62,6 @@ final class Froxlor
return self::VERSION;
}
/**
* return short basic version
*
* @return string
*/
public static function getShortVersion(): string
{
return explode(".", self::VERSION)[0] . '.' . explode(".", self::VERSION)[1];
}
/**
* return version + branding and database-version
*

View File

@@ -176,7 +176,7 @@ class FroxlorLogger
}
// clean log-text
$text = preg_replace("/[^\w @#\"':.,()\[\]+\-_\/\\\!]/i", "_", $text);
$text = preg_replace("/[^\w @#\"':.()\[\]+\-_\/\\\!]/i", "_", $text);
if (self::$crondebug_flag || ($action == FroxlorLogger::CRON_ACTION && $type <= LOG_WARNING)) {
echo "[" . $this->getLogLevelDesc($type) . "] " . $text . PHP_EOL;

View File

@@ -327,7 +327,7 @@ class Install
if (!preg_match('/^[^\r\n\t\f\0]*$/D', $name)) {
throw new Exception(lng('error.stringformaterror', ['admin_name']));
} elseif (empty(trim($loginname)) || !preg_match('/^[a-z][a-z0-9]+$/Di', $loginname)) {
} elseif (empty(trim($loginname)) || !preg_match('/^[a-z][a-z0-9]+$/', $loginname)) {
throw new Exception(lng('error.loginnameiswrong', [$loginname]));
} elseif (empty(trim($email)) || !Validate::validateEmail($email)) {
throw new Exception(lng('error.emailiswrong', [$email]));

View File

@@ -115,7 +115,7 @@ class Core
// create entries
$this->doDataEntries($pdo);
// create JSON array for config-services
$this->createJsonArray($pdo);
$this->createJsonArray();
if ($create_ud_str) {
$this->createUserdataParamStr();
}
@@ -435,14 +435,23 @@ class Core
// check currently used php version and set values of fpm/fcgid accordingly
if (defined('PHP_MAJOR_VERSION') && defined('PHP_MINOR_VERSION')) {
// php-fpm
$reload = "service php" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "-fpm restart";
$config_dir = "/etc/php/" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "/fpm/pool.d/";
// fcgid
if ($this->validatedData['distribution'] == 'bookworm') {
$binary = "/usr/bin/php-cgi" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;
// gentoo specific
if ($this->validatedData['distribution'] == 'gentoo') {
// php-fpm
$reload = "/etc/init.d/php-fpm restart";
$config_dir = "/etc/php/fpm-php" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "/fpm.d/";
// fcgid
$binary = "/usr/bin/php-cgi";
} else {
$binary = "/usr/bin/php" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "-cgi";
// php-fpm
$reload = "service php" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "-fpm restart";
$config_dir = "/etc/php/" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "/fpm/pool.d/";
// fcgid
if ($this->validatedData['distribution'] == 'bookworm') {
$binary = "/usr/bin/php-cgi" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;
} else {
$binary = "/usr/bin/php" . PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "-cgi";
}
}
$db_user->query("UPDATE `" . TABLE_PANEL_FPMDAEMONS . "` SET `reload_cmd` = '" . $reload . "', `config_dir` = '" . $config_dir . "' WHERE `id` ='1';");
$db_user->query("UPDATE `" . TABLE_PANEL_PHPCONFIGS . "` SET `binary` = '" . $binary . "';");
@@ -655,20 +664,9 @@ class Core
@umask($umask);
}
private function createJsonArray(&$db_user)
private function createJsonArray()
{
// use traffic analyzer and ftpserver from settings as we could define defaults in the lib/configfiles/*.xml templates
// which can be useful for third-party package-maintainer (e.g. other distros) to have more control
// over the installation defaults (less hardcoded values)
$custom_dependency = $db_user->query("
SELECT `varname`, `value` FROM `" . TABLE_PANEL_SETTINGS . "`
WHERE `settinggroup` = 'system' AND (`varname` = 'traffictool' OR `varname` = 'ftpserver')
");
$cd_result = $custom_dependency->fetchAll(\PDO::FETCH_KEY_PAIR);
$system_params = ["cron", "libnssextrausers", "logrotate"];
if (isset($cd_result['traffictool'])) {
$system_params[] = $cd_result['traffictool'];
}
$system_params = ["cron", "libnssextrausers", "logrotate", "goaccess"];
if ($this->validatedData['webserver_backend'] == 'php-fpm') {
$system_params[] = 'php-fpm';
} elseif ($this->validatedData['webserver_backend'] == 'fcgid') {
@@ -680,8 +678,7 @@ class Core
'http' => $this->validatedData['webserver'],
'smtp' => 'postfix_dovecot',
'mail' => 'dovecot_postfix2',
'antispam' => 'rspamd',
'ftp' => $cd_result['ftpserver'] ?? 'x',
'ftp' => 'proftpd',
'system' => $system_params
];
$_SESSION['installation']['json_params'] = json_encode($json_params);

View File

@@ -85,31 +85,27 @@ class Preconfig
}
}
}
/**
* Function getPreConfig
*
* outputs various form-field-arrays before the update process
* can be continued (asks for agreement whatever is being asked)
*
* @param bool $no_check
* @return array
*/
public static function getPreConfig(bool $no_check = false): array
public static function getPreConfig(): array
{
$preconfig = new self();
if ($preconfig->hasPreConfig()) {
if (!$no_check) {
$agree = [
'title' => 'Check',
'fields' => [
'update_changesagreed' => ['mandatory' => true, 'type' => 'checkrequired', 'value' => 1, 'label' => '<strong>I have read the update notifications above and I am aware of the changes made to my system.</strong>'],
'update_preconfig' => ['type' => 'hidden', 'value' => 1]
]
];
$preconfig->addToPreConfig($agree);
}
$agree = [
'title' => 'Check',
'fields' => [
'update_changesagreed' => ['mandatory' => true, 'type' => 'checkrequired', 'value' => 1, 'label' => '<strong>I have read the update notifications above and I am aware of the changes made to my system.</strong>'],
'update_preconfig' => ['type' => 'hidden', 'value' => 1]
]
];
$preconfig->addToPreConfig($agree);
return $preconfig->getData();
}
return [];

View File

@@ -25,7 +25,6 @@
namespace Froxlor\Install;
use Froxlor\FileDir;
use Froxlor\Froxlor;
use Froxlor\FroxlorLogger;
use Froxlor\Settings;
@@ -86,7 +85,7 @@ class Update
self::$update_tasks[self::$task_counter]['result'] = 1;
break;
default:
self::$update_tasks[self::$task_counter]['result'] = -1;
self::$update_tasks[self::$task_counter]['result'] = -1;
break;
}
@@ -137,36 +136,4 @@ class Update
{
return self::$task_counter;
}
public static function cleanOldFiles(array $to_clean)
{
self::showUpdateStep("Cleaning up old files");
$disabled = explode(',', ini_get('disable_functions'));
$exec_allowed = !in_array('exec', $disabled);
$del_list = "";
foreach ($to_clean as $filedir) {
$complete_filedir = Froxlor::getInstallDir() . $filedir;
if (file_exists($complete_filedir)) {
if ($exec_allowed) {
FileDir::safe_exec("rm -rf " . escapeshellarg($complete_filedir));
} else {
$del_list .= "rm -rf " . escapeshellarg($complete_filedir) . PHP_EOL;
}
}
}
if ($exec_allowed) {
self::lastStepStatus(0);
} else {
if (empty($del_list)) {
// none of the files existed
self::lastStepStatus(0);
} else {
self::lastStepStatus(
1,
'manual commands needed',
'Please run the following commands manually:<br><pre>' . $del_list . '</pre>'
);
}
}
}
}

View File

@@ -104,10 +104,6 @@ class MailLogParser
unset($matches);
$line = fgets($file_handle);
if (strpos($line, 'postfix') === false) {
continue;
}
$timestamp = $this->getLogTimestamp($line);
if ($this->startTime < $timestamp) {
if (preg_match("/postfix\/qmgr.*(?::|\])\s([A-Z\d]+).*from=<?(?:.*\@([a-zA-Z\d\.\-]+))?>?, size=(\d+),/", $line, $matches)) {
@@ -116,7 +112,7 @@ class MailLogParser
"domainFrom" => strtolower($matches[2]),
"size" => $matches[3]
];
} elseif (preg_match("/postfix\/(?:pipe|smtp|lmtp).*(?::|\])\s([A-Z\d]+).*to=<?(?:.*\@([a-zA-Z\d\.\-]+))?>?,/", $line, $matches)) {
} elseif (preg_match("/postfix\/(?:pipe|smtp).*(?::|\])\s([A-Z\d]+).*to=<?(?:.*\@([a-zA-Z\d\.\-]+))?>?,/", $line, $matches)) {
// Postfix to
if (array_key_exists($matches[1], $this->mails)) {
$this->mails[$matches[1]]["domainTo"] = strtolower($matches[2]);
@@ -153,7 +149,7 @@ class MailLogParser
private function getLogTimestamp($line)
{
$matches = null;
if (preg_match("/((?:[A-Z]{3}\s{1,2}\d{1,2}|\d{4}-\d{2}-\d{2}).\d{2}:\d{2}:\d{2})/i", $line, $matches)) {
if (preg_match("/((?:[A-Z]{3}\s{1,2}\d{1,2}|\d{4}-\d{2}-\d{2}) \d{2}:\d{2}:\d{2})/i", $line, $matches)) {
$timestamp = strtotime($matches[1]);
if ($timestamp > ($this->startTime + 60 * 60 * 24)) {
return strtotime($matches[1] . " -1 year");
@@ -262,10 +258,6 @@ class MailLogParser
unset($matches);
$line = fgets($file_handle);
if (strpos($line, 'dovecot') === false) {
continue;
}
$timestamp = $this->getLogTimestamp($line);
if ($this->startTime < $timestamp) {
if (preg_match("/dovecot.*(?::|\]) imap\(.*@([a-z0-9\.\-]+)\)(<\d+><[a-z0-9+\/=]+>)?:.*(?:in=(\d+) out=(\d+)|bytes=(\d+)\/(\d+))/i", $line, $matches)) {

View File

@@ -34,6 +34,27 @@ use voku\helper\AntiXSS;
class PhpHelper
{
private static $sort_key = 'id';
private static $sort_type = SORT_STRING;
/**
* sort an array by either natural or string sort and a given index where the value for comparison is found
*
* @param array $list
* @param string $key
*
* @return bool
*/
public static function sortListBy(array &$list, string $key = 'id'): bool
{
self::$sort_type = Settings::Get('panel.natsorting') == 1 ? SORT_NATURAL : SORT_STRING;
self::$sort_key = $key;
return usort($list, [
'self',
'sortListByGivenKey'
]);
}
/**
* Wrapper around htmlentities to handle arrays, with the advantage that you
* can select which fields should be handled by htmlentities
@@ -80,6 +101,35 @@ class PhpHelper
});
}
/**
* Replaces Strings in an array, with the advantage that you
* can select which fields should be str_replace'd
*
* @param string|array $search String or array of strings to search for
* @param string|array $replace String or array to replace with
* @param string|array $subject String or array The subject array
* @param string|array $fields string The fields which should be checked for, separated by spaces
*
* @return string|array The str_replace'd array
*/
public static function strReplaceArray($search, $replace, $subject, $fields = '')
{
if (is_array($subject)) {
if (!is_array($fields)) {
$fields = self::arrayTrim(explode(' ', $fields));
}
foreach ($subject as $field => $value) {
if ((!is_array($fields) || empty($fields)) || (in_array($field, $fields))) {
$subject[$field] = str_replace($search, $replace, $value);
}
}
} else {
$subject = str_replace($search, $replace, $subject);
}
return $subject;
}
/**
* froxlor php error handler
*
@@ -120,8 +170,9 @@ class PhpHelper
$err_display .= '</pre></p>';
// end later
$err_display .= '</div>';
// set errors to session
ErrorBag::addError($err_display);
// check for more existing errors
$errors = isset(UI::twig()->getGlobals()['global_errors']) ? UI::twig()->getGlobals()['global_errors'] : "";
UI::twig()->addGlobal('global_errors', $errors . $err_display);
// return true to ignore php standard error-handler
return true;
}
@@ -287,8 +338,7 @@ class PhpHelper
?string $max = '',
string $system = 'si',
string $retstring = '%01.2f %s'
): string
{
): string {
// Pick units
$systems = [
'si' => [
@@ -371,12 +421,8 @@ class PhpHelper
array $haystack,
array &$keys = [],
string $currentKey = ''
): bool
{
): bool {
foreach ($haystack as $key => $value) {
if (empty($value)) {
continue;
}
$pathkey = empty($currentKey) ? $key : $currentKey . '.' . $key;
if (is_array($value)) {
self::recursive_array_search($needle, $value, $keys, $pathkey);
@@ -420,9 +466,6 @@ class PhpHelper
'admin_pass',
'admin_pass_confirm',
'panel_password_special_char',
'old_password',
'new_password',
'new_password_confirm',
];
if (!empty($global)) {
$tmp = $global;
@@ -434,6 +477,19 @@ class PhpHelper
}
}
/**
* @param array $a
* @param array $b
* @return int
*/
private static function sortListByGivenKey(array $a, array $b): int
{
if (self::$sort_type == SORT_NATURAL) {
return strnatcasecmp($a[self::$sort_key], $b[self::$sort_key]);
}
return strcasecmp($a[self::$sort_key], $b[self::$sort_key]);
}
/**
* Generate php file from array.
*

View File

@@ -25,7 +25,6 @@
namespace Froxlor;
use Exception;
use Froxlor\Database\Database;
use PDO;
use PDOStatement;
@@ -132,12 +131,11 @@ class Settings
self::$conf = [
'enable_webupdate' => false,
'disable_otp_security_check' => false,
'display_php_errors' => false,
];
$configfile = Froxlor::getInstallDir() . '/lib/config.inc.php';
if (@file_exists($configfile) && is_readable($configfile)) {
self::$conf = array_merge(self::$conf, include $configfile);
self::$conf = include $configfile;
}
return true;
}
@@ -332,7 +330,7 @@ class Settings
}
}
public static function getAll(): array
public static function getAll() : array
{
self::init();
return self::$data;
@@ -340,14 +338,17 @@ class Settings
/**
* get value from config by identifier
* @throws Exception
*/
public static function Config(string $config)
{
self::init();
$result = self::$conf[$config] ?? null;
if (is_null($result)) {
throw new Exception('Unknown local config name "' . $config . '"');
$sstr = explode(".", $config);
$result = self::$conf;
foreach ($sstr as $key) {
$result = $result[$key] ?? null;
if (empty($result)) {
break;
}
}
return $result;
}

View File

@@ -36,7 +36,6 @@ use Froxlor\PhpHelper;
use Froxlor\Settings;
use Froxlor\System\Cronjob;
use Froxlor\System\IPTools;
use Froxlor\UI\Request;
use Froxlor\Validate\Validate;
use PDO;
@@ -226,17 +225,6 @@ class Store
return $returnvalue;
}
public static function storeSettingFieldInsertAntispamTask($fieldname, $fielddata, $newfieldvalue)
{
// first save the setting itself
$returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue);
if ($returnvalue !== false) {
Cronjob::inserttask(TaskId::REBUILD_RSPAMD);
}
return $returnvalue;
}
public static function storeSettingHostname($fieldname, $fielddata, $newfieldvalue)
{
$returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue);
@@ -466,7 +454,7 @@ class Store
}
// Delete file?
if ($fielddata['value'] !== "" && array_key_exists($fieldname . '_delete', $_POST) && Request::post($fieldname . '_delete')) {
if ($fielddata['value'] !== "" && array_key_exists($fieldname . '_delete', $_POST) && $_POST[$fieldname . '_delete']) {
@unlink(Froxlor::getInstallDir() . '/' . explode('?', $fielddata['value'], 2)[0]);
$save_to = '';
}

View File

@@ -134,15 +134,11 @@ class Cronjob
INSERT INTO `" . TABLE_PANEL_TASKS . "` SET `type` = :type, `data` = :data
");
if ($type == TaskId::REBUILD_VHOST || $type == TaskId::REBUILD_DNS || $type == TaskId::CREATE_FTP || $type == TaskId::REBUILD_RSPAMD || $type == TaskId::CREATE_QUOTA || $type == TaskId::REBUILD_CRON) {
if ($type == TaskId::REBUILD_VHOST || $type == TaskId::REBUILD_DNS || $type == TaskId::CREATE_FTP || $type == TaskId::CREATE_QUOTA || $type == TaskId::REBUILD_CRON) {
// 4 = bind -> if bind disabled -> no task
if ($type == TaskId::REBUILD_DNS && Settings::Get('system.bind_enable') == '0') {
return;
}
// 9 = rspamd -> if antispam disabled -> no task
if ($type == TaskId::REBUILD_RSPAMD && Settings::Get('antispam.activated') == '0') {
return;
}
// 10 = quota -> if quota disabled -> no task
if ($type == TaskId::CREATE_QUOTA && Settings::Get('system.diskquota_enabled') == '0') {
return;
@@ -183,7 +179,7 @@ class Cronjob
} elseif ($type == TaskId::DELETE_EMAIL_DATA && count($params) == 2 && $params[0] != '' && $params[1] != '') {
$data = [];
$data['loginname'] = $params[0];
$data['emailpath'] = $params[1];
$data['email'] = $params[1];
$data = json_encode($data);
Database::pexecute($ins_stmt, [
'type' => TaskId::DELETE_EMAIL_DATA,

View File

@@ -42,7 +42,7 @@ class Traffic
{
$trafficCollectionObj = (new Collection(TrafficAPI::class, $userinfo,
self::getParamsByRange($range, ['customer_traffic' => true])));
if (($userinfo['adminsession'] ?? 0) == 1) {
if ($userinfo['adminsession'] == 1) {
$trafficCollectionObj->has('customer', Customers::class, 'customerid', 'customerid');
}
$trafficCollection = $trafficCollectionObj->get();
@@ -58,17 +58,8 @@ class Traffic
$mail = $item['mail'];
$total = $http + $ftp + $mail;
if (empty($users[$item['customerid']])) {
$users[$item['customerid']] = [
'total' => 0.00,
'http' => 0.00,
'ftp' => 0.00,
'mail' => 0.00,
];
}
// per user total
if (($userinfo['adminsession'] ?? 0) == 1) {
if ($userinfo['adminsession'] == 1) {
$users[$item['customerid']]['loginname'] = $item['customer']['loginname'];
}
$users[$item['customerid']]['total'] += $total;
@@ -76,30 +67,6 @@ class Traffic
$users[$item['customerid']]['ftp'] += $ftp;
$users[$item['customerid']]['mail'] += $mail;
if (!$overview) {
if (empty($years[$item['year']])) {
$years[$item['year']] = [
'total' => 0.00,
'http' => 0.00,
'ftp' => 0.00,
'mail' => 0.00,
];
}
if (empty($months[$item['month'] . '/' . $item['year']])) {
$months[$item['month'] . '/' . $item['year']] = [
'total' => 0.00,
'http' => 0.00,
'ftp' => 0.00,
'mail' => 0.00,
];
}
if (empty($days[$item['day'] . '.' . $item['month'] . '.' . $item['year']])) {
$days[$item['day'] . '.' . $item['month'] . '.' . $item['year']] = [
'total' => 0.00,
'http' => 0.00,
'ftp' => 0.00,
'mail' => 0.00,
];
}
// per year
$years[$item['year']]['total'] += $total;
$years[$item['year']]['http'] += $http;
@@ -119,12 +86,7 @@ class Traffic
}
// calculate overview for given range from users
$metrics = [
'total' => 0.00,
'http' => 0.00,
'ftp' => 0.00,
'mail' => 0.00,
];
$metrics = [];
foreach ($users as $user) {
$metrics['total'] += $user['total'];
$metrics['http'] += $user['http'];

View File

@@ -34,36 +34,23 @@ use Froxlor\UI\Panel\UI;
class Domain
{
public static function domainEditLink(array $attributes): array
public static function domainLink(array $attributes)
{
$linker = UI::getLinker();
return [
'macro' => 'link',
'data' => [
'text' => $attributes['data'],
'href' => $linker->getLink([
'section' => 'domains',
'page' => 'domains',
'action' => 'edit',
'id' => $attributes['fields']['id'],
]),
'target' => '_blank'
]
];
return '<a href="https://' . $attributes['data'] . '" target="_blank">' . $attributes['data'] . '</a>';
}
public static function domainWithCustomerLink(array $attributes): string
public static function domainWithCustomerLink(array $attributes)
{
$linker = UI::getLinker();
$result = '<a href="https://' . $attributes['data'] . '" target="_blank">' . $attributes['data'] . '</a>';
if ((int)UI::getCurrentUser()['adminsession'] == 1 && $attributes['fields']['customerid']) {
$result .= ' (<a href="' . $linker->getLink([
'section' => 'customers',
'page' => 'customers',
'action' => 'su',
'sort' => $attributes['fields']['loginname'],
'id' => $attributes['fields']['customerid'],
]) . '">' . $attributes['fields']['loginname'] . '</a>)';
'section' => 'customers',
'page' => 'customers',
'action' => 'su',
'sort' => $attributes['fields']['loginname'],
'id' => $attributes['fields']['customerid'],
]) . '">' . $attributes['fields']['loginname'] . '</a>)';
}
return $result;
}
@@ -74,9 +61,6 @@ class Domain
if ($attributes['fields']['deactivated']) {
return lng('admin.deactivated');
}
if ($attributes['fields']['email_only']) {
return lng('domains.email_only');
}
// path or redirect
if (preg_match('/^https?\:\/\//', $attributes['fields']['documentroot'])) {
return [
@@ -125,12 +109,12 @@ class Domain
public static function canEdit(array $attributes): bool
{
return $attributes['fields']['caneditdomain'] && !$attributes['fields']['deactivated'];
return (bool)($attributes['fields']['caneditdomain'] && !$attributes['fields']['deactivated']);
}
public static function canViewLogs(array $attributes): bool
{
if ((int)$attributes['fields']['email_only'] == 0 && !$attributes['fields']['deactivated']) {
if ((!CurrentUser::isAdmin() || (CurrentUser::isAdmin() && (int)$attributes['fields']['email_only'] == 0)) && !$attributes['fields']['deactivated']) {
if ((int)UI::getCurrentUser()['adminsession'] == 0 && (bool)UI::getCurrentUser()['logviewenabled']) {
return true;
} elseif ((int)UI::getCurrentUser()['adminsession'] == 1) {
@@ -160,7 +144,6 @@ class Domain
&& $attributes['fields']['caneditdomain'] == '1'
&& Settings::Get('system.bind_enable') == '1'
&& Settings::Get('system.dnsenabled') == '1'
&& !$attributes['fields']['email_only']
&& !$attributes['fields']['deactivated'];
}
@@ -173,19 +156,17 @@ class Domain
public static function hasLetsEncryptActivated(array $attributes): bool
{
return ((bool)$attributes['fields']['letsencrypt'] && (int)$attributes['fields']['email_only'] == 0);
return ((bool)$attributes['fields']['letsencrypt'] && (!CurrentUser::isAdmin() || (CurrentUser::isAdmin() && (int)$attributes['fields']['email_only'] == 0)));
}
/**
* @throws \Exception
*/
public static function canEditSSL(array $attributes): bool
{
if (Settings::Get('system.use_ssl') == '1'
if (
Settings::Get('system.use_ssl') == '1'
&& DDomain::domainHasSslIpPort($attributes['fields']['id'])
&& (CurrentUser::isAdmin() || (!CurrentUser::isAdmin() && (int)$attributes['fields']['caneditdomain'] == 1))
&& (int)$attributes['fields']['caneditdomain'] == 1
&& (int)$attributes['fields']['letsencrypt'] == 0
&& !(int)$attributes['fields']['email_only']
&& (!CurrentUser::isAdmin() || (CurrentUser::isAdmin() && (int)$attributes['fields']['email_only'] == 0))
&& !$attributes['fields']['deactivated']
) {
return true;
@@ -216,15 +197,15 @@ class Domain
],
];
// specified certificate for domain
if ($attributes['fields']['domain_hascert'] == 1) {
// specified certificate for domain
$result['icon'] .= ' text-success';
} elseif ($attributes['fields']['domain_hascert'] == 2) {
// shared certificates (e.g. subdomain of domain where certificate is specified)
} // shared certificates (e.g. subdomain of domain where certificate is specified)
elseif ($attributes['fields']['domain_hascert'] == 2) {
$result['icon'] .= ' text-warning';
$result['title'] .= "\n" . lng('panel.ssleditor_infoshared');
} elseif ($attributes['fields']['domain_hascert'] == 0) {
// no certificate specified, using global fallbacks (IPs and Ports or if empty SSL settings)
} // no certificate specified, using global fallbacks (IPs and Ports or if empty SSL settings)
elseif ($attributes['fields']['domain_hascert'] == 0) {
$result['icon'] .= ' text-danger';
$result['title'] .= "\n" . lng('panel.ssleditor_infoglobal');
}
@@ -236,19 +217,16 @@ class Domain
public static function listIPs(array $attributes): string
{
if (!empty($attributes['fields']['ipsandports'])) {
if (isset($attributes['fields']['ipsandports']) && !empty($attributes['fields']['ipsandports'])) {
$iplist = "";
foreach ($attributes['fields']['ipsandports'] as $ipport) {
$iplist .= $ipport['ip'] . ':' . $ipport['port'] . '<br>';
}
return $iplist;
}
return lng('panel.listing_empty');
return lng('panel.empty');
}
/**
* @throws \Exception
*/
public static function getPhpConfigName(array $attributes): string
{
$sel_stmt = Database::prepare("SELECT `description` FROM `" . TABLE_PANEL_PHPCONFIGS . "` WHERE `id` = :id");
@@ -256,11 +234,11 @@ class Domain
if ((int)UI::getCurrentUser()['adminsession'] == 1) {
$linker = UI::getLinker();
$result = '<a href="' . $linker->getLink([
'section' => 'phpsettings',
'page' => 'overview',
'searchfield' => 'c.id',
'searchtext' => $attributes['data'],
]) . '">' . $phpconfig['description'] . '</a>';
'section' => 'phpsettings',
'page' => 'overview',
'searchfield' => 'c.id',
'searchtext' => $attributes['data'],
]) . '">' . $phpconfig['description'] . '</a>';
} else {
$result = $phpconfig['description'];
}

View File

@@ -52,14 +52,6 @@ class Text
];
}
public static function type2fa(array $attributes): array
{
return [
'macro' => 'type2fa',
'data' => (int)$attributes['data']
];
}
public static function customerfullname(array $attributes): string
{
return User::getCorrectFullUserDetails($attributes['fields'], true);

View File

@@ -273,10 +273,6 @@ class Form
if (\Froxlor\Validate\Form::validateFieldDefinition($groupdetails)) {
// Check fields for plausibility
foreach ($groupdetails['fields'] as $fieldname => $fielddetails) {
if (!isset($submitted_fields[$fieldname])) {
// skip unset fields due to unavailability for this system/settings-set
continue;
}
if (!$only_enabledisable || ($only_enabledisable && isset($fielddetails['overview_option']))) {
if (($plausibility_check = self::checkPlausibilityFormField($fieldname, $fielddetails, $submitted_fields[$fieldname], $submitted_fields)) !== false) {
if (is_array($plausibility_check) && isset($plausibility_check[0])) {

View File

@@ -33,9 +33,10 @@ class HTML
/**
* Build Navigation Sidebar
*
* @param array $navigation data
* @param array $userinfo the userinfo of the user
*
* @param
* array navigation data
* @param
* array userinfo the userinfo of the user
* @return array the content of the navigation bar according to user-permissions
*/
public static function buildNavigation(array $navigation, array $userinfo)
@@ -43,19 +44,12 @@ class HTML
$returnvalue = [];
// sanitize user-given input (url-manipulation)
$req_page = Request::get('page');
if (!empty($req_page) && is_array($req_page)) {
$req_page = (string)array_shift($req_page);
if (isset($_GET['page']) && is_array($_GET['page'])) {
$_GET['page'] = (string)$_GET['page'][0];
}
// need to preserve this
$_GET['page'] = $req_page;
$req_action = Request::get('action');
if (!empty($req_action) && is_array($req_action)) {
$req_action = (string)array_shift($req_action);
if (isset($_GET['action']) && is_array($_GET['action'])) {
$_GET['action'] = (string)$_GET['action'][0];
}
// need to preserve this
$_GET['action'] = $req_action;
foreach ($navigation as $box) {
if ((!isset($box['show_element']) || $box['show_element'] === true) && (!isset($box['required_resources']) || $box['required_resources'] == '' || (isset($userinfo[$box['required_resources']]) && ((int)$userinfo[$box['required_resources']] > 0 || $userinfo[$box['required_resources']] == '-1')))) {
@@ -75,7 +69,7 @@ class HTML
}
if (
((empty($req_page) && substr_count($element['url'], "page=") == 0) || (!empty($req_page) && substr_count($element['url'], "page=" . $req_page) > 0))
((empty($_GET['page']) && substr_count($element['url'], "page=") == 0) || (isset($_GET['page']) && substr_count($element['url'], "page=" . $_GET['page']) > 0))
&& substr_count($element['url'], basename($_SERVER["SCRIPT_FILENAME"])) > 0
) {
$active = true;

View File

@@ -61,12 +61,11 @@ class Pagination
*/
public function __construct(
array $fields = [],
int $total_entries = 0,
int $perPage = 20,
int $total_entries = 0,
int $perPage = 20,
array $default_sorting = [],
array $pagination_additional_params = []
)
{
) {
$this->fields = $fields;
$this->entries = $total_entries;
$this->perPage = $perPage;
@@ -81,13 +80,12 @@ class Pagination
$orderfields = array_keys($fields);
$this->searchfield = $orderfields[0];
}
$searchtext = Request::any('searchtext');
if (isset($searchtext) && (preg_match('/[-_@\p{L}\p{N}*.]+$/u', $searchtext) || $searchtext === '')) {
$this->searchtext = trim($searchtext);
if (isset($_REQUEST['searchtext']) && (preg_match('/[-_@\p{L}\p{N}*.]+$/u',
$_REQUEST['searchtext']) || $_REQUEST['searchtext'] === '')) {
$this->searchtext = trim($_REQUEST['searchtext']);
}
$searchfield = Request::any('searchfield');
if (isset($searchfield) && isset($fields[$searchfield])) {
$this->searchfield = $searchfield;
if (isset($_REQUEST['searchfield']) && isset($fields[$_REQUEST['searchfield']])) {
$this->searchfield = $_REQUEST['searchfield'];
}
if (!empty($this->searchtext) && !empty($this->searchfield)) {
$this->addSearch($this->searchtext, $this->searchfield);
@@ -96,13 +94,11 @@ class Pagination
}
// check other ordering requests
$sortorder = Request::any('sortorder');
if (!empty($sortorder) && (strtolower($sortorder) == 'desc' || strtolower($sortorder) == 'asc')) {
$this->sortorder = strtoupper($sortorder);
if (isset($_REQUEST['sortorder']) && (strtolower($_REQUEST['sortorder']) == 'desc' || strtolower($_REQUEST['sortorder']) == 'asc')) {
$this->sortorder = strtoupper($_REQUEST['sortorder']);
}
$sortfield = Request::any('sortfield');
if (!empty($sortfield) && isset($fields[$sortfield])) {
$this->sortfield = $sortfield;
if (isset($_REQUEST['sortfield']) && isset($fields[$_REQUEST['sortfield']])) {
$this->sortfield = $_REQUEST['sortfield'];
$this->addOrderBy($this->sortfield, $this->sortorder);
} else {
// add default ordering by given order
@@ -122,9 +118,8 @@ class Pagination
}
// check current page / pages
$pageno = Request::any('pageno');
if (!empty($pageno) && intval($pageno) != 0) {
$this->pageno = intval($pageno);
if (isset($_REQUEST['pageno']) && intval($_REQUEST['pageno']) != 0) {
$this->pageno = intval($_REQUEST['pageno']);
}
if (($this->pageno - 1) * Settings::Get('panel.paging') > $this->entries) {
$this->pageno = 1;

View File

@@ -30,16 +30,14 @@ use voku\helper\AntiXSS;
class Request
{
private static $cleaned = false;
/**
* Get key from current $_GET or $_POST request.
*
* @param $key
* @param mixed|null $default
* @param string|null $default
* @return mixed|string|null
*/
public static function any($key, $default = null)
public static function any($key, string $default = null)
{
self::cleanAll();
@@ -50,10 +48,10 @@ class Request
* Get key from current $_GET request.
*
* @param $key
* @param mixed|null $default
* @param string|null $default
* @return mixed|string|null
*/
public static function get($key, $default = null)
public static function get($key, string $default = null)
{
self::cleanAll();
@@ -64,56 +62,37 @@ class Request
* Get key from current $_POST request.
*
* @param $key
* @param mixed|null $default
* @param string|null $default
* @return mixed|string|null
*/
public static function post($key, $default = null)
public static function post($key, string $default = null)
{
self::cleanAll();
return $_POST[$key] ?? $default;
}
/**
* return complete $_POST array
*
* @return array
*/
public static function postAll()
{
self::cleanAll();
return $_POST ?? [];
}
/**
* Check for xss attempts and clean important globals and
* unsetting every variable registered in $_REQUEST and as variable itself
*/
public static function cleanAll()
{
if (!self::$cleaned) {
foreach ($_REQUEST as $key => $value) {
if (isset($$key)) {
unset($$key);
}
foreach ($_REQUEST as $key => $value) {
if (isset($$key)) {
unset($$key);
}
unset($value);
$antiXss = new AntiXSS();
$antiXss->addNeverAllowedRegex([
'{{(.*)}}' => ''
]);
// check $_GET
PhpHelper::cleanGlobal($_GET, $antiXss);
// check $_POST
PhpHelper::cleanGlobal($_POST, $antiXss);
// check $_COOKIE
PhpHelper::cleanGlobal($_COOKIE, $antiXss);
self::$cleaned = true;
}
unset($value);
$antiXss = new AntiXSS();
// check $_GET
PhpHelper::cleanGlobal($_GET, $antiXss);
// check $_POST
PhpHelper::cleanGlobal($_POST, $antiXss);
// check $_COOKIE
PhpHelper::cleanGlobal($_COOKIE, $antiXss);
}
/**

View File

@@ -139,7 +139,7 @@ class Response
exit;
}
public static function dynamicError($message, bool $nosession = false)
public static function dynamicError($message)
{
$_SESSION['requestData'] = $_POST;
$link_ref = '';
@@ -147,8 +147,7 @@ class Response
$link_ref = htmlentities($_SERVER['HTTP_REFERER']);
}
$tpl = $nosession ? 'misc/alert_nosession.html.twig' : 'misc/alert.html.twig';
UI::view($tpl, [
UI::view('misc/alert.html.twig', [
'type' => 'danger',
'btntype' => 'light',
'heading' => lng('error.error'),

View File

@@ -28,7 +28,6 @@ namespace Froxlor\Validate;
use Froxlor\Database\Database;
use Froxlor\FileDir;
use Froxlor\Settings;
use Froxlor\UI\Request;
class Check
{
@@ -74,7 +73,7 @@ class Check
// interface is to be enabled
if ((int)$newfieldvalue == 1) {
// check for POST value of the other field == 1 (active)
if ((int)Request::post($check_array[$fieldname]['other_post_field'], 0) == 1) {
if (isset($_POST[$check_array[$fieldname]['other_post_field']]) && (int)$_POST[$check_array[$fieldname]['other_post_field']] == 1) {
// the other interface is activated already and STAYS activated
if ((int)Settings::Get($check_array[$fieldname]['other_enabled']) == 1) {
$returnvalue = [
@@ -84,12 +83,8 @@ class Check
} else {
// fcgid is being validated before fpm -> "ask" fpm about its state
if ($fieldname == 'system_mod_fcgid_enabled') {
$returnvalue = self::checkFcgidPhpFpm(
'system_phpfpm_enabled',
null,
$check_array[$fieldname]['other_post_field'],
null
);
$returnvalue = self::checkFcgidPhpFpm('system_phpfpm_enabled', null,
$check_array[$fieldname]['other_post_field'], null);
} else {
// not, bot are nogo
$returnvalue = $returnvalue = [
@@ -122,16 +117,8 @@ class Check
$mysql_access_host_array = array_unique(array_map('trim', explode(',', $newfieldvalue)));
foreach ($mysql_access_host_array as $host_entry) {
if (Validate::validate_ip2(
$host_entry,
true,
'invalidip',
true,
true,
true,
true,
false
) == false && Validate::validateDomain($host_entry) == false && Validate::validateLocalHostname($host_entry) == false && $host_entry != '%') {
if (Validate::validate_ip2($host_entry, true, 'invalidip', true, true, true, true,
false) == false && Validate::validateDomain($host_entry) == false && Validate::validateLocalHostname($host_entry) == false && $host_entry != '%') {
return [
self::FORMFIELDS_PLAUSIBILITY_CHECK_ERROR,
'invalidmysqlhost',
@@ -217,11 +204,8 @@ class Check
}
// neither dir can be within the other nor can they be equal
if (substr($newdir, 0, strlen($cdir)) == $cdir || substr(
$cdir,
0,
strlen($newdir)
) == $newdir || $newdir == $cdir) {
if (substr($newdir, 0, strlen($cdir)) == $cdir || substr($cdir, 0,
strlen($newdir)) == $newdir || $newdir == $cdir) {
$returnvalue = [
self::FORMFIELDS_PLAUSIBILITY_CHECK_ERROR,
'fcgidpathcannotbeincustomerdoc'
@@ -280,11 +264,8 @@ class Check
}
$returnvalue = [];
if (Validate::validateUsername(
$newfieldvalue,
Settings::Get('panel.unix_names'),
Database::getSqlUsernameLength() - strlen($allnewfieldvalues['customer_mysqlprefix'])
) === true) {
if (Validate::validateUsername($newfieldvalue, Settings::Get('panel.unix_names'),
Database::getSqlUsernameLength() - strlen($allnewfieldvalues['customer_mysqlprefix'])) === true) {
$returnvalue = [
self::FORMFIELDS_PLAUSIBILITY_CHECK_OK
];
@@ -349,7 +330,7 @@ class Check
];
}
// check if the pgp public key is a valid key
putenv('GNUPGHOME=' . sys_get_temp_dir());
putenv('GNUPGHOME='.sys_get_temp_dir());
if (gnupg_import(gnupg_init(), $newfieldvalue) === false) {
return [
self::FORMFIELDS_PLAUSIBILITY_CHECK_ERROR,

View File

@@ -232,7 +232,7 @@ class Data
{
$returnvalue = true;
if (isset($fielddata['select_mode']) && $fielddata['select_mode'] == 'multiple') {
if (isset($fielddata['option_mode']) && $fielddata['option_mode'] == 'multiple') {
$options = explode(',', $newfieldvalue);
foreach ($options as $option) {
$returnvalue = ($returnvalue && isset($fielddata['select_var'][$option]));
@@ -241,13 +241,13 @@ class Data
$returnvalue = isset($fielddata['select_var'][$newfieldvalue]);
}
if ($returnvalue === true || (isset($fielddata['visible']) && $fielddata['visible'] == false)) {
if ($returnvalue === true || $fielddata['visible'] == false) {
return true;
} else {
if (isset($fielddata['option_emptyallowed']) && $fielddata['option_emptyallowed']) {
return true;
}
return 'not in option (field: ' . $fieldname . ')';
return 'not in option';
}
}

Some files were not shown because too many files have changed in this diff Show More