Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1347b877a5 | ||
|
|
a862307bce | ||
|
|
2f03eee9aa | ||
|
|
f4183b020b | ||
|
|
9a3d88e8c9 | ||
|
|
c9460fd58f | ||
|
|
6ef532b470 | ||
|
|
5909401cdd | ||
|
|
809e8ef45b | ||
|
|
0a091a99e8 | ||
|
|
e299fbe665 | ||
|
|
67e8b622d8 | ||
|
|
ce509273d4 | ||
|
|
bcf588a2e4 | ||
|
|
f08d540e66 | ||
|
|
e06db3d8c5 | ||
|
|
c5c04ebe9c | ||
|
|
c9faa38f6c | ||
|
|
c188f047dc | ||
|
|
775d50306c | ||
|
|
3821144c3b | ||
|
|
a1da70c221 | ||
|
|
bb2db0fed0 | ||
|
|
9680f24640 | ||
|
|
c732fbd81b | ||
|
|
7980b8d14d | ||
|
|
13e88f5b47 | ||
|
|
031596301b | ||
|
|
b34ab45746 | ||
|
|
dbf83c6f24 | ||
|
|
4cb974839c | ||
|
|
1fa714ef2c |
8
.github/workflows/build-mariadb.yml
vendored
8
.github/workflows/build-mariadb.yml
vendored
@@ -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/"
|
||||
|
||||
13
.github/workflows/build-mysql.yml
vendored
13
.github/workflows/build-mysql.yml
vendored
@@ -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'@'%';"
|
||||
|
||||
9
2fa.php
9
2fa.php
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
@@ -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'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
146
actions/admin/settings/180.dkim.php
Normal file
146
actions/admin/settings/180.dkim.php
Normal 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
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
@@ -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> ';
|
||||
$return['antispam_activated'] = [
|
||||
'type' => 'checkbox',
|
||||
'value' => 1,
|
||||
'checked' => 0,
|
||||
'label' => $question,
|
||||
'prior_infotext' => $description
|
||||
];
|
||||
}
|
||||
|
||||
$preconfig['fields'] = $return;
|
||||
return $preconfig;
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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' => [
|
||||
[
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
641
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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, [
|
||||
|
||||
@@ -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
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
185
index.php
@@ -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'])) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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 ';
|
||||
$return['system_le_domain_dnscheck'] = [
|
||||
'type' => 'checkbox',
|
||||
'value' => 1,
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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='
|
||||
]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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']);
|
||||
|
||||
@@ -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) == '.') {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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']);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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"
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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("
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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']
|
||||
]);
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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' => []
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 [];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 [];
|
||||
|
||||
@@ -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>'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 = '';
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'];
|
||||
|
||||
@@ -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'];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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])) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user