mirror of
https://github.com/Froxlor/Froxlor.git
synced 2024-09-21 10:27:29 +00:00
implementation start of rspam/antispam feature
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
parent
63bbcd4e00
commit
b15f99b1e1
111
actions/admin/settings/180.antispam.php
Normal file
111
actions/admin/settings/180.antispam.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?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'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
@ -1,146 +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\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
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
163
composer.lock
generated
163
composer.lock
generated
@ -2559,16 +2559,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.17.1",
|
||||
"version": "v4.18.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
|
||||
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
|
||||
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2609,22 +2609,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0"
|
||||
},
|
||||
"time": "2023-08-13T19:53:39+00:00"
|
||||
"time": "2023-12-10T21:03:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pdepend/pdepend",
|
||||
"version": "2.16.0",
|
||||
"version": "2.16.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pdepend/pdepend.git",
|
||||
"reference": "8dfc0c46529e2073fa97986552f80646eedac562"
|
||||
"reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/8dfc0c46529e2073fa97986552f80646eedac562",
|
||||
"reference": "8dfc0c46529e2073fa97986552f80646eedac562",
|
||||
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58",
|
||||
"reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2637,7 +2637,6 @@
|
||||
"require-dev": {
|
||||
"easy-doc/easy-doc": "0.0.0|^1.2.3",
|
||||
"gregwar/rst": "^1.0",
|
||||
"phpunit/phpunit": "^4.8.36|^5.7.27",
|
||||
"squizlabs/php_codesniffer": "^2.0.0"
|
||||
},
|
||||
"bin": [
|
||||
@ -2667,7 +2666,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/pdepend/pdepend/issues",
|
||||
"source": "https://github.com/pdepend/pdepend/tree/2.16.0"
|
||||
"source": "https://github.com/pdepend/pdepend/tree/2.16.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2675,7 +2674,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-29T08:52:35+00:00"
|
||||
"time": "2023-12-17T18:09:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@ -2913,22 +2912,22 @@
|
||||
},
|
||||
{
|
||||
"name": "phpmd/phpmd",
|
||||
"version": "2.14.1",
|
||||
"version": "2.15.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpmd/phpmd.git",
|
||||
"reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8"
|
||||
"reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpmd/phpmd/zipball/442fc2c34edcd5198b442d8647c7f0aec3afabe8",
|
||||
"reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8",
|
||||
"url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0",
|
||||
"reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0",
|
||||
"ext-xml": "*",
|
||||
"pdepend/pdepend": "^2.15.1",
|
||||
"pdepend/pdepend": "^2.16.1",
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
@ -2937,7 +2936,6 @@
|
||||
"ext-simplexml": "*",
|
||||
"gregwar/rst": "^1.0",
|
||||
"mikey179/vfsstream": "^1.6.8",
|
||||
"phpunit/phpunit": "^4.8.36 || ^5.7.27",
|
||||
"squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2"
|
||||
},
|
||||
"bin": [
|
||||
@ -2985,7 +2983,7 @@
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.org/phpmd",
|
||||
"issues": "https://github.com/phpmd/phpmd/issues",
|
||||
"source": "https://github.com/phpmd/phpmd/tree/2.14.1"
|
||||
"source": "https://github.com/phpmd/phpmd/tree/2.15.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2993,20 +2991,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-28T13:07:44+00:00"
|
||||
"time": "2023-12-11T08:22:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.46",
|
||||
"version": "1.10.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "90d3d25c5b98b8068916bbf08ce42d5cb6c54e70"
|
||||
"reference": "06a98513ac72c03e8366b5a0cb00750b487032e4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/90d3d25c5b98b8068916bbf08ce42d5cb6c54e70",
|
||||
"reference": "90d3d25c5b98b8068916bbf08ce42d5cb6c54e70",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4",
|
||||
"reference": "06a98513ac72c03e8366b5a0cb00750b487032e4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3055,27 +3053,27 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-28T14:57:26+00:00"
|
||||
"time": "2023-12-13T10:59:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.29",
|
||||
"version": "9.2.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
|
||||
"reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089",
|
||||
"reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^4.15",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=7.3",
|
||||
"phpunit/php-file-iterator": "^3.0.3",
|
||||
"phpunit/php-text-template": "^2.0.2",
|
||||
@ -3125,7 +3123,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -3133,7 +3131,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-19T04:57:46+00:00"
|
||||
"time": "2023-12-22T06:47:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -3378,16 +3376,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.6.13",
|
||||
"version": "9.6.15",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be"
|
||||
"reference": "05017b80304e0eb3f31d90194a563fd53a6021f1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be",
|
||||
"reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1",
|
||||
"reference": "05017b80304e0eb3f31d90194a563fd53a6021f1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3461,7 +3459,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -3477,7 +3475,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-19T05:39:22+00:00"
|
||||
"time": "2023-12-01T16:55:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@ -3722,20 +3720,20 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
"version": "2.0.2",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/complexity.git",
|
||||
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
|
||||
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
|
||||
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
|
||||
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.7",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
@ -3767,7 +3765,7 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/complexity",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -3775,7 +3773,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-26T15:52:27+00:00"
|
||||
"time": "2023-12-22T06:19:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
@ -4049,20 +4047,20 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/lines-of-code",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
|
||||
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
|
||||
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
|
||||
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
|
||||
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.6",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
@ -4094,7 +4092,7 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -4102,7 +4100,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-28T06:42:11+00:00"
|
||||
"time": "2023-12-22T06:20:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-enumerator",
|
||||
@ -4507,16 +4505,16 @@
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.7.2",
|
||||
"version": "3.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879"
|
||||
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
|
||||
"reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879",
|
||||
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5805f7a4e4958dbb5e944ef1e6edae0a303765e7",
|
||||
"reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4526,7 +4524,7 @@
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/phpcs",
|
||||
@ -4545,22 +4543,45 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Greg Sherwood",
|
||||
"role": "lead"
|
||||
"role": "Former lead"
|
||||
},
|
||||
{
|
||||
"name": "Juliette Reinders Folmer",
|
||||
"role": "Current lead"
|
||||
},
|
||||
{
|
||||
"name": "Contributors",
|
||||
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
||||
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
|
||||
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
|
||||
"keywords": [
|
||||
"phpcs",
|
||||
"standards",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
|
||||
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
|
||||
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
|
||||
"issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
|
||||
"security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
|
||||
"source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
|
||||
"wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
|
||||
},
|
||||
"time": "2023-02-22T23:07:41+00:00"
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/PHPCSStandards",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/jrfnl",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://opencollective.com/php_codesniffer",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-08T12:32:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
@ -4643,16 +4664,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/dependency-injection",
|
||||
"version": "v5.4.32",
|
||||
"version": "v5.4.33",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dependency-injection.git",
|
||||
"reference": "d5d48f215ed73f7973d01256b9a2fac729bef759"
|
||||
"reference": "14969a558cd6382b2a12b14b20ef9a851a02da79"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/d5d48f215ed73f7973d01256b9a2fac729bef759",
|
||||
"reference": "d5d48f215ed73f7973d01256b9a2fac729bef759",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/14969a558cd6382b2a12b14b20ef9a851a02da79",
|
||||
"reference": "14969a558cd6382b2a12b14b20ef9a851a02da79",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4712,7 +4733,7 @@
|
||||
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.32"
|
||||
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.33"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -4728,7 +4749,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-29T06:58:28+00:00"
|
||||
"time": "2023-11-30T08:15:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
|
@ -245,6 +245,15 @@ if ($page == 'email_domain') {
|
||||
|
||||
if (isset($result['email']) && $result['email'] != '') {
|
||||
if (isset($_POST['send']) && $_POST['send'] == 'send') {
|
||||
try {
|
||||
Emails::getLocal($userinfo, [
|
||||
'id' => $id,
|
||||
'spam_tag_level' => $_POST['spam_tag_level'] ?? \Froxlor\Cron\Mail\Rspamd::DEFAULT_MARK_LVL,
|
||||
'spam_kill_level' => $_POST['spam_kill_level'] ?? \Froxlor\Cron\Mail\Rspamd::DEFAULT_REJECT_LVL
|
||||
])->update();
|
||||
} catch (Exception $e) {
|
||||
Response::dynamicError($e->getMessage());
|
||||
}
|
||||
Response::redirectTo($filename, [
|
||||
'page' => $page
|
||||
]);
|
||||
@ -291,6 +300,54 @@ if ($page == 'email_domain') {
|
||||
'editid' => $id
|
||||
]);
|
||||
}
|
||||
} elseif ($action == 'togglebypass' && $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,
|
||||
'bypass_spam' => ($result['bypass_spam'] == '1' ? 0 : 1)
|
||||
])->update();
|
||||
} catch (Exception $e) {
|
||||
Response::dynamicError($e->getMessage());
|
||||
}
|
||||
Response::redirectTo($filename, [
|
||||
'page' => $page,
|
||||
'domainid' => $email_domainid,
|
||||
'action' => 'edit',
|
||||
'id' => $id,
|
||||
]);
|
||||
} elseif ($action == 'togglegreylist' && $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,
|
||||
'policy_greylist' => ($result['policy_greylist'] == '1' ? 0 : 1)
|
||||
])->update();
|
||||
} catch (Exception $e) {
|
||||
Response::dynamicError($e->getMessage());
|
||||
}
|
||||
Response::redirectTo($filename, [
|
||||
'page' => $page,
|
||||
'domainid' => $email_domainid,
|
||||
'action' => 'edit',
|
||||
'id' => $id,
|
||||
]);
|
||||
} elseif ($action == 'togglecatchall' && $id != 0) {
|
||||
try {
|
||||
$json_result = Emails::getLocal($userinfo, [
|
||||
|
@ -94,6 +94,10 @@ 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,
|
||||
`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;
|
||||
@ -380,22 +384,18 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES
|
||||
('logger', 'logfile', ''),
|
||||
('logger', 'logtypes', 'syslog,mysql'),
|
||||
('logger', 'severity', '1'),
|
||||
('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'),
|
||||
('antispam', 'activated', '0'),
|
||||
('antispam', 'config_file', '/etc/rspamd/local.d/froxlor_settings.conf'),
|
||||
('antispam', 'reload_command', 'service rspamd restart'),
|
||||
('antispam', 'dkim_keylength', '1024'),
|
||||
('admin', 'show_news_feed', '0'),
|
||||
('admin', 'show_version_login', '0'),
|
||||
('admin', 'show_version_footer', '0'),
|
||||
('caa', 'caa_entry', ''),
|
||||
('spf', 'use_spf', '0'),
|
||||
('spf', 'spf_entry', 'v=spf1 a mx -all'),
|
||||
('dkim', 'dkim_algorithm', 'all'),
|
||||
('dkim', 'dkim_keylength', '1024'),
|
||||
('dkim', 'dkim_servicetype', '0'),
|
||||
('dkim', 'dkim_notes', ''),
|
||||
('dmarc', 'use_dmarc', '0'),
|
||||
('dmarc', 'dmarc_entry', 'v=DMARC1; p=none;'),
|
||||
('defaultwebsrverrhandler', 'enabled', '0'),
|
||||
('defaultwebsrverrhandler', 'err401', ''),
|
||||
('defaultwebsrverrhandler', 'err403', ''),
|
||||
@ -726,6 +726,8 @@ opcache.validate_timestamps'),
|
||||
('panel', 'logo_overridecustom', '0'),
|
||||
('panel', 'settings_mode', '0'),
|
||||
('panel', 'menu_collapsed', '1'),
|
||||
('panel', 'version', '2.2.0-dev1'),
|
||||
('panel', 'db_version', '202312230');
|
||||
('panel', 'version', '2.1.4'),
|
||||
('panel', 'db_version', '202312120');
|
||||
|
||||
|
@ -99,7 +99,6 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
||||
}
|
||||
Update::lastStepStatus(0);
|
||||
|
||||
Update::showUpdateStep("Cleaning up old files");
|
||||
$to_clean = array(
|
||||
"install/lib",
|
||||
"install/lng",
|
||||
@ -121,30 +120,7 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
||||
"lng/swedish.lng.php",
|
||||
"scripts",
|
||||
);
|
||||
$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::cleanOldFiles($to_clean);
|
||||
|
||||
Update::showUpdateStep("Adding new settings");
|
||||
$panel_settings_mode = isset($_POST['panel_settings_mode']) ? (int)$_POST['panel_settings_mode'] : 0;
|
||||
|
@ -149,7 +149,6 @@ 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",
|
||||
@ -175,33 +174,8 @@ if (Froxlor::isDatabaseVersion('202311260')) {
|
||||
"templates/Froxlor/user/change_theme.html.twig",
|
||||
"tests/Backup/CustomerBackupsTest.php"
|
||||
);
|
||||
$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::cleanOldFiles($to_clean);
|
||||
|
||||
Froxlor::updateToDbVersion('202312050');
|
||||
}
|
||||
|
||||
@ -216,7 +190,6 @@ 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",
|
||||
@ -225,33 +198,8 @@ if (Froxlor::isDatabaseVersion('202312050')) {
|
||||
"lib/configfiles/buster.xml",
|
||||
"lib/configfiles/bionic.xml",
|
||||
);
|
||||
$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::cleanOldFiles($to_clean);
|
||||
|
||||
Froxlor::updateToDbVersion('202312100');
|
||||
}
|
||||
|
||||
|
68
install/updates/froxlor/update_2.2.inc.php
Normal file
68
install/updates/froxlor/update_2.2.inc.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?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\FileDir;
|
||||
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.x')) {
|
||||
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");
|
||||
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam', `varname` = 'activated' WHERE `settinggroup` = 'dkim' AND `varname` = 'use_dkim';");
|
||||
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `settinggroup` = 'antispam', `varname` = 'reload_command' 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';");
|
||||
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');
|
||||
}
|
@ -23,31 +23,26 @@
|
||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||
*/
|
||||
|
||||
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'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
use Froxlor\Install\Update;
|
||||
|
||||
$preconfig = [
|
||||
'title' => '2.2.x updates',
|
||||
'fields' => []
|
||||
];
|
||||
$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)?';
|
||||
$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;
|
@ -55,6 +55,7 @@ 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");
|
||||
|
@ -1407,7 +1407,7 @@ class Domains extends ApiCommand implements ResourceEntity
|
||||
$zonefile = $result['zonefile'];
|
||||
}
|
||||
|
||||
if (Settings::Get('dkim.use_dkim') != '1') {
|
||||
if (Settings::Get('antispam.activated') != '1') {
|
||||
$dkim = $result['dkim'];
|
||||
}
|
||||
|
||||
|
@ -28,10 +28,12 @@ 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;
|
||||
@ -49,6 +51,14 @@ 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 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
|
||||
@ -74,6 +84,10 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
$domain = $this->getParam('domain');
|
||||
|
||||
// parameters
|
||||
$spam_tag_level = $this->getParam('spam_tag_level', true, '7.0');
|
||||
$spam_kill_level = $this->getParam('spam_kill_level', 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, '');
|
||||
|
||||
@ -140,11 +154,19 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
}
|
||||
}
|
||||
|
||||
$spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1,2})?$/', '', [7.0], true);
|
||||
$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("
|
||||
INSERT INTO `" . TABLE_MAIL_VIRTUAL . "` SET
|
||||
`customerid` = :cid,
|
||||
`email` = :email,
|
||||
`email_full` = :email_full,
|
||||
`spam_tag_level` = :spam_tag_level,
|
||||
`spam_kill_level` = :spam_kill_level,
|
||||
`bypass_spam` = :bypass_spam,
|
||||
`policy_greylist` = :policy_greylist,
|
||||
`iscatchall` = :iscatchall,
|
||||
`domainid` = :domainid,
|
||||
`description` = :description
|
||||
@ -153,6 +175,10 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
"cid" => $customer['customerid'],
|
||||
"email" => $email,
|
||||
"email_full" => $email_full,
|
||||
"spam_tag_level" => $spam_tag_level,
|
||||
"spam_kill_level" => $spam_kill_level,
|
||||
"bypass_spam" => $bypass_spam,
|
||||
"policy_greylist" => $policy_greylist,
|
||||
"iscatchall" => $iscatchall,
|
||||
"domainid" => $domain_check['id'],
|
||||
"description" => $description
|
||||
@ -162,6 +188,7 @@ 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', [
|
||||
@ -194,7 +221,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
$customer_ids = $this->getAllowedCustomerIds('email');
|
||||
$params['idea'] = ($id <= 0 ? $emailaddr : $id);
|
||||
|
||||
$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`
|
||||
$result_stmt = Database::prepare("SELECT v.*, 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) . ")
|
||||
@ -220,6 +247,14 @@ 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 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
|
||||
@ -255,6 +290,10 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
$id = $result['id'];
|
||||
|
||||
// parameters
|
||||
$spam_tag_level = $this->getParam('spam_tag_level', true, $result['spam_tag_level']);
|
||||
$spam_kill_level = $this->getParam('spam_kill_level', 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']);
|
||||
|
||||
@ -284,19 +323,34 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
$email = $result['email_full'];
|
||||
}
|
||||
|
||||
$spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1,2})?$/', '', [7.0], true);
|
||||
$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 , `iscatchall` = :caflag, `description` = :description
|
||||
UPDATE `" . TABLE_MAIL_VIRTUAL . "` SET
|
||||
`email` = :email ,
|
||||
`spam_tag_level` = :spam_tag_level,
|
||||
`spam_kill_level` = :spam_kill_level,
|
||||
`bypass_spam` = :bypass_spam,
|
||||
`policy_greylist` = :policy_greylist,
|
||||
`iscatchall` = :caflag,
|
||||
`description` = :description
|
||||
WHERE `customerid`= :cid AND `id`= :id
|
||||
");
|
||||
$params = [
|
||||
"email" => $email,
|
||||
"spam_tag_level" => $spam_tag_level,
|
||||
"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', [
|
||||
@ -334,7 +388,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
$result = [];
|
||||
$query_fields = [];
|
||||
$result_stmt = Database::prepare("
|
||||
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`
|
||||
SELECT m.*, 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`)
|
||||
|
@ -43,9 +43,7 @@ final class ConfigServices extends CliCommand
|
||||
{
|
||||
private $yes_to_all_supported = [
|
||||
'bookworm',
|
||||
'bionic',
|
||||
'bullseye',
|
||||
'buster',
|
||||
'focal',
|
||||
'jammy',
|
||||
];
|
||||
@ -172,8 +170,8 @@ final class ConfigServices extends CliCommand
|
||||
$distributions_select_data = [];
|
||||
|
||||
//set default os.
|
||||
$os_dist = ['ID' => 'bullseye'];
|
||||
$os_version = ['0' => '11'];
|
||||
$os_dist = ['ID' => 'bookworm'];
|
||||
$os_version = ['0' => '12'];
|
||||
$os_default = $os_dist['ID'];
|
||||
|
||||
//read os-release
|
||||
|
@ -27,10 +27,13 @@ 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;
|
||||
@ -50,7 +53,8 @@ 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('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');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,6 +76,15 @@ 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';
|
||||
@ -349,6 +362,57 @@ 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, 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, 9 = re-generate rspamd configs, 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,6 +77,7 @@ 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';
|
||||
@ -95,7 +96,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::CREATE_QUOTA, TaskId::REBUILD_CRON])) {
|
||||
if (in_array($ttr, [TaskId::REBUILD_VHOST, TaskId::REBUILD_DNS, TaskId::REBUILD_RSPAMD, TaskId::CREATE_QUOTA, TaskId::REBUILD_CRON])) {
|
||||
Cronjob::inserttask($ttr);
|
||||
$jobs[] = 'tasks';
|
||||
} else {
|
||||
|
@ -117,85 +117,6 @@ 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("
|
||||
|
216
lib/Froxlor/Cron/Mail/Rspamd.php
Normal file
216
lib/Froxlor/Cron/Mail/Rspamd.php
Normal file
@ -0,0 +1,216 @@
|
||||
<?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('dkim.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'] = 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";
|
||||
$this->frx_settings_file .= ' rewrite_subject = ' . $email['spam_tag_level'] . ';' . "\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,9 +25,11 @@
|
||||
|
||||
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;
|
||||
@ -40,6 +42,9 @@ use PDO;
|
||||
class TasksCron extends FroxlorCron
|
||||
{
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function run()
|
||||
{
|
||||
/**
|
||||
@ -98,6 +103,11 @@ 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
|
||||
@ -266,13 +276,7 @@ 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();
|
||||
}
|
||||
|
||||
@ -448,4 +452,13 @@ class TasksCron extends FroxlorCron
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function rebuildAntiSpamConfigs()
|
||||
{
|
||||
$antispam = new Rspamd(FroxlorLogger::getInstanceOf());
|
||||
$antispam->writeConfigs();
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,12 @@ 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
|
||||
*/
|
||||
|
@ -32,7 +32,7 @@ class Customer
|
||||
{
|
||||
|
||||
/**
|
||||
* Get value of a a specific field from a given customer
|
||||
* Get value of a specific field from a given customer
|
||||
*
|
||||
* @param int $customerid
|
||||
* @param string $varname
|
||||
|
@ -120,16 +120,14 @@ class Dns
|
||||
if ($domain['isemaildomain'] == '1') {
|
||||
self::addRequiredEntry('@', 'MX', $required_entries);
|
||||
if (Settings::Get('system.dns_createmailentry')) {
|
||||
foreach (
|
||||
[
|
||||
foreach ([
|
||||
'imap',
|
||||
'pop3',
|
||||
'mail',
|
||||
'smtp'
|
||||
] as $record
|
||||
) {
|
||||
foreach (
|
||||
[
|
||||
foreach ([
|
||||
'AAAA',
|
||||
'A'
|
||||
] as $type
|
||||
@ -152,9 +150,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
|
||||
]);
|
||||
@ -163,7 +161,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
|
||||
@ -181,7 +179,7 @@ class Dns
|
||||
// check for SPF content later
|
||||
self::addRequiredEntry('@SPF@.' . $sub_record, 'TXT', $required_entries);
|
||||
}
|
||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||
if (Settings::Get('antispam.activated') == '1' && $domain['dkim'] == '1') {
|
||||
// check for DKIM content later
|
||||
self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey.' . $sub_record, 'TXT', $required_entries);
|
||||
}
|
||||
@ -218,7 +216,7 @@ class Dns
|
||||
// check for SPF content later
|
||||
self::addRequiredEntry('@SPF@', 'TXT', $required_entries);
|
||||
}
|
||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||
if (Settings::Get('antispam.activated') == '1' && $domain['dkim'] == '1') {
|
||||
// check for DKIM content later
|
||||
self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey', 'TXT', $required_entries);
|
||||
}
|
||||
@ -229,17 +227,25 @@ 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' && $entry['record'] == '@' && (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
|
||||
unset($required_entries[$entry['type']][md5("@SPF@")]);
|
||||
}
|
||||
@ -248,32 +254,36 @@ class Dns
|
||||
$primary_ns = $entry['content'];
|
||||
}
|
||||
// check for CNAME on @, www- or wildcard-Alias and remove A/AAAA record accordingly
|
||||
foreach (
|
||||
[
|
||||
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']))) {
|
||||
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 (
|
||||
[
|
||||
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']))) {
|
||||
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)]);
|
||||
}
|
||||
@ -310,8 +320,11 @@ 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']);
|
||||
}
|
||||
}
|
||||
@ -376,9 +389,7 @@ class Dns
|
||||
|
||||
// TXT (SPF and DKIM)
|
||||
if (array_key_exists("TXT", $required_entries)) {
|
||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||
$dkim_entries = self::generateDkimEntries($domain);
|
||||
}
|
||||
$dkim_entries = self::generateDkimEntries($domain);
|
||||
|
||||
foreach ($required_entries as $type => $records) {
|
||||
if ($type == 'TXT') {
|
||||
@ -471,8 +482,10 @@ 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
|
||||
@ -499,8 +512,12 @@ 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;
|
||||
}
|
||||
@ -527,43 +544,11 @@ class Dns
|
||||
{
|
||||
$zone_dkim = [];
|
||||
|
||||
if (Settings::Get('dkim.use_dkim') == '1' && $domain['dkim'] == '1' && $domain['dkim_pubkey'] != '') {
|
||||
if (Settings::Get('antispam.activated') == '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(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_txt .= 'k=rsa;p=' . trim($domain['dkim_pubkey']) . ';';
|
||||
// dkim-entry
|
||||
$zone_dkim[] = $dkim_txt;
|
||||
}
|
||||
|
77
lib/Froxlor/ErrorBag.php
Normal file
77
lib/Froxlor/ErrorBag.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?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 (!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.1.4';
|
||||
const VERSION = '2.2.0-dev1';
|
||||
|
||||
// Database version (YYYYMMDDC where C is a daily counter)
|
||||
const DBVERSION = '202312120';
|
||||
const DBVERSION = '202312230';
|
||||
|
||||
// Distribution branding-tag (used for Debian etc.)
|
||||
const BRANDING = '';
|
||||
|
||||
const DOCS_URL = 'https://docs.froxlor.org/v2.1/';
|
||||
const DOCS_URL = 'https://docs.froxlor.org/v2.2/';
|
||||
|
||||
/**
|
||||
* return path to where froxlor is installed, e.g.
|
||||
|
@ -674,6 +674,7 @@ class Core
|
||||
'http' => $this->validatedData['webserver'],
|
||||
'smtp' => 'postfix_dovecot',
|
||||
'mail' => 'dovecot_postfix2',
|
||||
'antispam' => 'rspamd',
|
||||
'ftp' => 'proftpd',
|
||||
'system' => $system_params
|
||||
];
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
namespace Froxlor\Install;
|
||||
|
||||
use Froxlor\FileDir;
|
||||
use Froxlor\Froxlor;
|
||||
use Froxlor\FroxlorLogger;
|
||||
use Froxlor\Settings;
|
||||
@ -85,7 +86,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;
|
||||
}
|
||||
|
||||
@ -136,4 +137,36 @@ 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>'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,27 +34,6 @@ 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
|
||||
@ -101,35 +80,6 @@ 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
|
||||
*
|
||||
@ -170,9 +120,8 @@ class PhpHelper
|
||||
$err_display .= '</pre></p>';
|
||||
// end later
|
||||
$err_display .= '</div>';
|
||||
// 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);
|
||||
// set errors to session
|
||||
ErrorBag::addError($err_display);
|
||||
// return true to ignore php standard error-handler
|
||||
return true;
|
||||
}
|
||||
@ -338,7 +287,8 @@ class PhpHelper
|
||||
?string $max = '',
|
||||
string $system = 'si',
|
||||
string $retstring = '%01.2f %s'
|
||||
): string {
|
||||
): string
|
||||
{
|
||||
// Pick units
|
||||
$systems = [
|
||||
'si' => [
|
||||
@ -421,7 +371,8 @@ class PhpHelper
|
||||
array $haystack,
|
||||
array &$keys = [],
|
||||
string $currentKey = ''
|
||||
): bool {
|
||||
): bool
|
||||
{
|
||||
foreach ($haystack as $key => $value) {
|
||||
$pathkey = empty($currentKey) ? $key : $currentKey . '.' . $key;
|
||||
if (is_array($value)) {
|
||||
@ -476,19 +427,6 @@ 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,6 +25,7 @@
|
||||
|
||||
namespace Froxlor;
|
||||
|
||||
use Exception;
|
||||
use Froxlor\Database\Database;
|
||||
use PDO;
|
||||
use PDOStatement;
|
||||
@ -131,6 +132,7 @@ class Settings
|
||||
self::$conf = [
|
||||
'enable_webupdate' => false,
|
||||
'disable_otp_security_check' => false,
|
||||
'display_php_errors' => false,
|
||||
];
|
||||
|
||||
$configfile = Froxlor::getInstallDir() . '/lib/config.inc.php';
|
||||
@ -330,7 +332,7 @@ class Settings
|
||||
}
|
||||
}
|
||||
|
||||
public static function getAll() : array
|
||||
public static function getAll(): array
|
||||
{
|
||||
self::init();
|
||||
return self::$data;
|
||||
@ -338,17 +340,14 @@ class Settings
|
||||
|
||||
/**
|
||||
* get value from config by identifier
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function Config(string $config)
|
||||
{
|
||||
self::init();
|
||||
$sstr = explode(".", $config);
|
||||
$result = self::$conf;
|
||||
foreach ($sstr as $key) {
|
||||
$result = $result[$key] ?? null;
|
||||
if (empty($result)) {
|
||||
break;
|
||||
}
|
||||
$result = self::$conf[$config] ?? null;
|
||||
if (is_null($result)) {
|
||||
throw new Exception('Unknown local config name "' . $config . '"');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
@ -225,6 +225,17 @@ 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);
|
||||
|
@ -134,11 +134,15 @@ 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::CREATE_QUOTA || $type == TaskId::REBUILD_CRON) {
|
||||
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) {
|
||||
// 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;
|
||||
|
@ -42,7 +42,7 @@ class Traffic
|
||||
{
|
||||
$trafficCollectionObj = (new Collection(TrafficAPI::class, $userinfo,
|
||||
self::getParamsByRange($range, ['customer_traffic' => true])));
|
||||
if ($userinfo['adminsession'] == 1) {
|
||||
if (($userinfo['adminsession'] ?? 0) == 1) {
|
||||
$trafficCollectionObj->has('customer', Customers::class, 'customerid', 'customerid');
|
||||
}
|
||||
$trafficCollection = $trafficCollectionObj->get();
|
||||
@ -58,8 +58,17 @@ 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'] == 1) {
|
||||
if (($userinfo['adminsession'] ?? 0) == 1) {
|
||||
$users[$item['customerid']]['loginname'] = $item['customer']['loginname'];
|
||||
}
|
||||
$users[$item['customerid']]['total'] += $total;
|
||||
@ -67,6 +76,30 @@ 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;
|
||||
@ -86,7 +119,12 @@ class Traffic
|
||||
}
|
||||
|
||||
// calculate overview for given range from users
|
||||
$metrics = [];
|
||||
$metrics = [
|
||||
'total' => 0.00,
|
||||
'http' => 0.00,
|
||||
'ftp' => 0.00,
|
||||
'mail' => 0.00,
|
||||
];
|
||||
foreach ($users as $user) {
|
||||
$metrics['total'] += $user['total'];
|
||||
$metrics['http'] += $user['http'];
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
namespace Froxlor\UI\Callbacks;
|
||||
|
||||
use Froxlor\CurrentUser;
|
||||
use Froxlor\Database\Database;
|
||||
use Froxlor\Domain\Domain as DDomain;
|
||||
use Froxlor\FileDir;
|
||||
@ -33,23 +34,36 @@ use Froxlor\UI\Panel\UI;
|
||||
|
||||
class Domain
|
||||
{
|
||||
public static function domainLink(array $attributes)
|
||||
public static function domainEditLink(array $attributes): array
|
||||
{
|
||||
return '<a href="https://' . $attributes['data'] . '" target="_blank">' . $attributes['data'] . '</a>';
|
||||
$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'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public static function domainWithCustomerLink(array $attributes)
|
||||
public static function domainWithCustomerLink(array $attributes): string
|
||||
{
|
||||
$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;
|
||||
}
|
||||
@ -108,12 +122,12 @@ class Domain
|
||||
|
||||
public static function canEdit(array $attributes): bool
|
||||
{
|
||||
return (bool)($attributes['fields']['caneditdomain'] && !$attributes['fields']['deactivated']);
|
||||
return $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) {
|
||||
@ -155,17 +169,19 @@ 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'])
|
||||
&& (int)$attributes['fields']['caneditdomain'] == 1
|
||||
&& (int)$attributes['fields']['letsencrypt'] == 0
|
||||
&& (int)$attributes['fields']['email_only'] == 0
|
||||
&& (!CurrentUser::isAdmin() || (CurrentUser::isAdmin() && (int)$attributes['fields']['email_only'] == 0))
|
||||
&& !$attributes['fields']['deactivated']
|
||||
) {
|
||||
return true;
|
||||
@ -196,15 +212,15 @@ class Domain
|
||||
],
|
||||
];
|
||||
|
||||
// specified certificate for domain
|
||||
if ($attributes['fields']['domain_hascert'] == 1) {
|
||||
// specified certificate for domain
|
||||
$result['icon'] .= ' text-success';
|
||||
} // shared certificates (e.g. subdomain of domain where certificate is specified)
|
||||
elseif ($attributes['fields']['domain_hascert'] == 2) {
|
||||
} elseif ($attributes['fields']['domain_hascert'] == 2) {
|
||||
// shared certificates (e.g. subdomain of domain where certificate is specified)
|
||||
$result['icon'] .= ' text-warning';
|
||||
$result['title'] .= "\n" . lng('panel.ssleditor_infoshared');
|
||||
} // no certificate specified, using global fallbacks (IPs and Ports or if empty SSL settings)
|
||||
elseif ($attributes['fields']['domain_hascert'] == 0) {
|
||||
} elseif ($attributes['fields']['domain_hascert'] == 0) {
|
||||
// no certificate specified, using global fallbacks (IPs and Ports or if empty SSL settings)
|
||||
$result['icon'] .= ' text-danger';
|
||||
$result['title'] .= "\n" . lng('panel.ssleditor_infoglobal');
|
||||
}
|
||||
@ -216,7 +232,7 @@ class Domain
|
||||
|
||||
public static function listIPs(array $attributes): string
|
||||
{
|
||||
if (isset($attributes['fields']['ipsandports']) && !empty($attributes['fields']['ipsandports'])) {
|
||||
if (!empty($attributes['fields']['ipsandports'])) {
|
||||
$iplist = "";
|
||||
foreach ($attributes['fields']['ipsandports'] as $ipport) {
|
||||
$iplist .= $ipport['ip'] . ':' . $ipport['port'] . '<br>';
|
||||
@ -226,6 +242,9 @@ class Domain
|
||||
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");
|
||||
@ -233,11 +252,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'];
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
namespace Froxlor\UI\Callbacks;
|
||||
|
||||
use Froxlor\CurrentUser;
|
||||
use Froxlor\Settings;
|
||||
|
||||
class Style
|
||||
@ -68,7 +69,7 @@ class Style
|
||||
$termination_css = 'table-danger';
|
||||
}
|
||||
}
|
||||
$deactivated = $attributes['fields']['deactivated'] || $attributes['fields']['customer_deactivated'];
|
||||
$deactivated = $attributes['fields']['deactivated'] || (CurrentUser::isAdmin() && $attributes['fields']['customer_deactivated']);
|
||||
return $deactivated ? 'table-info' : $termination_css;
|
||||
}
|
||||
|
||||
|
@ -90,9 +90,10 @@ class Text
|
||||
public static function customerNoteDetailModal(array $attributes): array
|
||||
{
|
||||
$note = $attributes['fields']['custom_notes'] ?? '';
|
||||
$key = $attributes['fields']['customerid'] ?? $attributes['fields']['adminid'];
|
||||
return [
|
||||
'entry' => $attributes['fields']['id'],
|
||||
'id' => 'cnModal' . $attributes['fields']['id'],
|
||||
'entry' => $key,
|
||||
'id' => 'cnModal' . $key,
|
||||
'title' => lng('usersettings.custom_notes.title') . ': ' . ($attributes['fields']['loginname'] ?? $attributes['fields']['adminname']),
|
||||
'body' => nl2br(Markdown::cleanCustomNotes($note))
|
||||
];
|
||||
|
@ -217,7 +217,8 @@ class Form
|
||||
{
|
||||
$returnvalue = [];
|
||||
if (is_array($fielddata) && isset($fielddata['type']) && $fielddata['type'] == 'select') {
|
||||
if ((!is_array($fielddata['select_var']) || empty($fielddata['select_var'])) && (isset($fielddata['option_options_method']))) {
|
||||
if ((empty($fielddata['select_var']) || !is_array($fielddata['select_var'])) && (isset($fielddata['option_options_method']))
|
||||
) {
|
||||
$returnvalue['select_var'] = call_user_func($fielddata['option_options_method']);
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class Response
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function dynamicError($message)
|
||||
public static function dynamicError($message, bool $nosession = false)
|
||||
{
|
||||
$_SESSION['requestData'] = $_POST;
|
||||
$link_ref = '';
|
||||
@ -147,7 +147,8 @@ class Response
|
||||
$link_ref = htmlentities($_SERVER['HTTP_REFERER']);
|
||||
}
|
||||
|
||||
UI::view('misc/alert.html.twig', [
|
||||
$tpl = $nosession ? 'misc/alert_nosession.html.twig' : 'misc/alert.html.twig';
|
||||
UI::view($tpl, [
|
||||
'type' => 'danger',
|
||||
'btntype' => 'light',
|
||||
'heading' => lng('error.error'),
|
||||
|
@ -23,4 +23,12 @@ return [
|
||||
* Default: false
|
||||
*/
|
||||
'disable_otp_security_check' => false,
|
||||
|
||||
/**
|
||||
* For debugging/development purposes only.
|
||||
* Enable to display all php related issue (notices, warnings, etc.; depending on php.ini) for froxlor itself
|
||||
*
|
||||
* Default: false
|
||||
*/
|
||||
'display_php_errors' => false,
|
||||
];
|
||||
|
@ -1657,7 +1657,7 @@ data_directory = /var/lib/postfix
|
||||
# for the case of a subdomain, $mydomain *must* be equal to $myhostname,
|
||||
# otherwise you cannot use the main domain for virtual transport.
|
||||
# also check the note about $mydomain below.
|
||||
myhostname = mail.$mydomain
|
||||
myhostname = $mydomain
|
||||
#myhostname = virtual.domain.tld
|
||||
|
||||
# The mydomain parameter specifies the local internet domain name.
|
||||
@ -1751,8 +1751,8 @@ inet_interfaces = all
|
||||
#
|
||||
# See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS".
|
||||
#
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost
|
||||
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
|
||||
mydestination = $myhostname, localhost.$mydomain, localhost
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
|
||||
# mail.$mydomain, www.$mydomain, ftp.$mydomain
|
||||
|
||||
@ -2561,6 +2561,107 @@ plugin {
|
||||
</include>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- Antispam services -->
|
||||
<service type="antispam" title="Antispam">
|
||||
<!-- general RSpamd commands -->
|
||||
<general>
|
||||
<commands index="1">
|
||||
<command><![CDATA[mkdir -p /etc/apt/keyrings]]></command>
|
||||
<command><![CDATA[wget -O- https://rspamd.com/apt-stable/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/rspamd.gpg > /dev/null]]></command>
|
||||
<command><![CDATA[echo "deb [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ bookworm main" > /etc/apt/sources.list.d/rspamd.list]]></command>
|
||||
<command><![CDATA[echo "deb-src [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ bookworm main" >> /etc/apt/sources.list.d/rspamd.list]]></command>
|
||||
<command><![CDATA[apt-get update]]></command>
|
||||
</commands>
|
||||
<installs index="1">
|
||||
<install><![CDATA[DEBIAN_FRONTEND=noninteractive apt-get -yq --no-install-recommends install rspamd]]></install>
|
||||
</installs>
|
||||
<commands index="2">
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/local.d/]]></command>
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/override.d/]]></command>
|
||||
<command><![CDATA[mkdir -p mkdir /var/lib/rspamd/dkim/]]></command>
|
||||
</commands>
|
||||
<files index="1">
|
||||
<file name="/etc/rspamd/local.d/actions.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
# Set rewrite subject to this value (%s is replaced by the original subject)
|
||||
subject = "***SPAM*** %s"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/arc.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
try_fallback = true;
|
||||
### Enable DKIM signing for alias sender addresses
|
||||
allow_username_mismatch = true;
|
||||
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
|
||||
selector_map = "/etc/rspamd/dkim_selectors.map";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/milter_headers.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
use = ["x-spamd-bar", "x-spam-level", "authentication-results"];
|
||||
authenticated_headers = ["authentication-results"];
|
||||
extended_spam_headers = true
|
||||
skip_local = false
|
||||
skip_authenticated = false
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/replies.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
## If a user has replied to an email, don’t mark other emails in the same thread as spam
|
||||
action = "no action";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/settings.conf"
|
||||
chown="root:root" chmod="0644" backup="true">
|
||||
<content><![CDATA[
|
||||
## Feel free to include your own settings or adjustments here, for example:
|
||||
#whitelist {
|
||||
# priority = low;
|
||||
# rcpt = "postmaster@example.com";
|
||||
# want_spam = yes;
|
||||
#}
|
||||
|
||||
## Include froxlor generated settings
|
||||
.include(try=true,priority=1,duplicate=merge) "{{settings.antispam.config_file}}"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
</files>
|
||||
<commands index="3">
|
||||
<command><![CDATA[cp /etc/rspamd/local.d/arc.conf /etc/rspamd/local.d/dkim_signing.conf]]></command>
|
||||
<command><![CDATA[postconf -e "milter_protocol = 6"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_default_action = accept"]]></command>
|
||||
<command><![CDATA[postconf -e "smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[chown -R _rspamd:_rspamd /var/lib/rspamd/dkim]]></command>
|
||||
<command><![CDATA[chmod 440 /var/lib/rspamd/dkim/*]]></command>
|
||||
<command><![CDATA[service rspamd restart]]></command>
|
||||
<command><![CDATA[service postfix restart]]></command>
|
||||
</commands>
|
||||
</general>
|
||||
<!-- rspamd -->
|
||||
<daemon name="rspamd" title="Rspamd" default="true">
|
||||
<include>//service[@type='antispam']/general/commands[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/installs[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=2]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/files[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=3]
|
||||
</include>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- FTP services -->
|
||||
<service type="ftp" title="{{lng.admin.configfiles.ftp}}">
|
||||
<!-- Proftpd -->
|
||||
|
@ -1657,7 +1657,7 @@ data_directory = /var/lib/postfix
|
||||
# for the case of a subdomain, $mydomain *must* be equal to $myhostname,
|
||||
# otherwise you cannot use the main domain for virtual transport.
|
||||
# also check the note about $mydomain below.
|
||||
myhostname = mail.$mydomain
|
||||
myhostname = $mydomain
|
||||
#myhostname = virtual.domain.tld
|
||||
|
||||
# The mydomain parameter specifies the local internet domain name.
|
||||
@ -1751,8 +1751,8 @@ inet_interfaces = all
|
||||
#
|
||||
# See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS".
|
||||
#
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost
|
||||
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
|
||||
mydestination = $myhostname, localhost.$mydomain, localhost
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
|
||||
# mail.$mydomain, www.$mydomain, ftp.$mydomain
|
||||
|
||||
@ -4131,6 +4131,106 @@ plugin {
|
||||
</include>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- Antispam services -->
|
||||
<service type="antispam" title="Antispam">
|
||||
<!-- general RSpamd commands -->
|
||||
<general>
|
||||
<commands index="1">
|
||||
<command><![CDATA[mkdir -p /etc/apt/keyrings]]></command>
|
||||
<command><![CDATA[wget -O- https://rspamd.com/apt-stable/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/rspamd.gpg > /dev/null]]></command>
|
||||
<command><![CDATA[echo "deb [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ bullseye main" > /etc/apt/sources.list.d/rspamd.list]]></command>
|
||||
<command><![CDATA[echo "deb-src [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ bullseye main" >> /etc/apt/sources.list.d/rspamd.list]]></command>
|
||||
<command><![CDATA[apt-get update]]></command>
|
||||
</commands>
|
||||
<installs index="1">
|
||||
<install><![CDATA[DEBIAN_FRONTEND=noninteractive apt-get -yq --no-install-recommends install rspamd]]></install>
|
||||
</installs>
|
||||
<commands index="2">
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/local.d/]]></command>
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/override.d/]]></command>
|
||||
<command><![CDATA[mkdir -p mkdir /var/lib/rspamd/dkim/]]></command>
|
||||
</commands>
|
||||
<files index="1">
|
||||
<file name="/etc/rspamd/local.d/actions.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
# Set rewrite subject to this value (%s is replaced by the original subject)
|
||||
subject = "***SPAM*** %s"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/arc.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
try_fallback = true;
|
||||
### Enable DKIM signing for alias sender addresses
|
||||
allow_username_mismatch = true;
|
||||
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
|
||||
selector_map = "/etc/rspamd/dkim_selectors.map";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/milter_headers.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
use = ["x-spamd-bar", "x-spam-level", "authentication-results"];
|
||||
authenticated_headers = ["authentication-results"];
|
||||
extended_spam_headers = true
|
||||
skip_local = false
|
||||
skip_authenticated = false
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/replies.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
## If a user has replied to an email, don’t mark other emails in the same thread as spam
|
||||
action = "no action";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/settings.conf"
|
||||
chown="root:root" chmod="0644" backup="true">
|
||||
<content><![CDATA[
|
||||
## Feel free to include your own settings or adjustments here, for example:
|
||||
#whitelist {
|
||||
# priority = low;
|
||||
# rcpt = "postmaster@example.com";
|
||||
# want_spam = yes;
|
||||
#}
|
||||
|
||||
## Include froxlor generated settings
|
||||
.include(try=true,priority=1,duplicate=merge) "{{settings.antispam.config_file}}"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
</files>
|
||||
<commands index="3">
|
||||
<command><![CDATA[cp /etc/rspamd/local.d/arc.conf /etc/rspamd/local.d/dkim_signing.conf]]></command>
|
||||
<command><![CDATA[postconf -e "milter_protocol = 6"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_default_action = accept"]]></command>
|
||||
<command><![CDATA[postconf -e "smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[chown -R _rspamd:_rspamd /var/lib/rspamd/dkim]]></command>
|
||||
<command><![CDATA[chmod 440 /var/lib/rspamd/dkim/*]]></command>
|
||||
<command><![CDATA[service rspamd restart]]></command>
|
||||
</commands>
|
||||
</general>
|
||||
<!-- rspamd -->
|
||||
<daemon name="rspamd" title="Rspamd" default="true">
|
||||
<include>//service[@type='antispam']/general/commands[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/installs[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=2]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/files[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=3]
|
||||
</include>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- FTP services -->
|
||||
<service type="ftp" title="{{lng.admin.configfiles.ftp}}">
|
||||
<!-- Proftpd -->
|
||||
|
@ -1642,7 +1642,7 @@ compatibility_level = 2
|
||||
# for the case of a subdomain, $mydomain *must* be equal to $myhostname,
|
||||
# otherwise you cannot use the main domain for virtual transport.
|
||||
# also check the note about $mydomain below.
|
||||
myhostname = mail.$mydomain
|
||||
myhostname = $mydomain
|
||||
#myhostname = virtual.domain.tld
|
||||
|
||||
# The mydomain parameter specifies the local internet domain name.
|
||||
@ -1656,8 +1656,8 @@ myhostname = mail.$mydomain
|
||||
# FQDN from Froxlor
|
||||
mydomain = <SERVERNAME>
|
||||
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost
|
||||
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
|
||||
mydestination = $myhostname, localhost.$mydomain, localhost
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
|
||||
# mail.$mydomain, www.$mydomain, ftp.$mydomain
|
||||
|
||||
@ -3354,6 +3354,106 @@ plugin {
|
||||
</include>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- Antispam services -->
|
||||
<service type="antispam" title="Antispam">
|
||||
<!-- general RSpamd commands -->
|
||||
<general>
|
||||
<commands index="1">
|
||||
<command><![CDATA[mkdir -p /etc/apt/keyrings]]></command>
|
||||
<command><![CDATA[wget -O- https://rspamd.com/apt-stable/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/rspamd.gpg > /dev/null]]></command>
|
||||
<command><![CDATA[echo "deb [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ focal main" > /etc/apt/sources.list.d/rspamd.list]]></command>
|
||||
<command><![CDATA[echo "deb-src [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ focal main" >> /etc/apt/sources.list.d/rspamd.list]]></command>
|
||||
<command><![CDATA[apt-get update]]></command>
|
||||
</commands>
|
||||
<installs index="1">
|
||||
<install><![CDATA[DEBIAN_FRONTEND=noninteractive apt-get -yq --no-install-recommends install rspamd]]></install>
|
||||
</installs>
|
||||
<commands index="2">
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/local.d/]]></command>
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/override.d/]]></command>
|
||||
<command><![CDATA[mkdir -p mkdir /var/lib/rspamd/dkim/]]></command>
|
||||
</commands>
|
||||
<files index="1">
|
||||
<file name="/etc/rspamd/local.d/actions.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
# Set rewrite subject to this value (%s is replaced by the original subject)
|
||||
subject = "***SPAM*** %s"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/arc.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
try_fallback = true;
|
||||
### Enable DKIM signing for alias sender addresses
|
||||
allow_username_mismatch = true;
|
||||
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
|
||||
selector_map = "/etc/rspamd/dkim_selectors.map";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/milter_headers.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
use = ["x-spamd-bar", "x-spam-level", "authentication-results"];
|
||||
authenticated_headers = ["authentication-results"];
|
||||
extended_spam_headers = true
|
||||
skip_local = false
|
||||
skip_authenticated = false
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/replies.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
## If a user has replied to an email, don’t mark other emails in the same thread as spam
|
||||
action = "no action";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/settings.conf"
|
||||
chown="root:root" chmod="0644" backup="true">
|
||||
<content><![CDATA[
|
||||
## Feel free to include your own settings or adjustments here, for example:
|
||||
#whitelist {
|
||||
# priority = low;
|
||||
# rcpt = "postmaster@example.com";
|
||||
# want_spam = yes;
|
||||
#}
|
||||
|
||||
## Include froxlor generated settings
|
||||
.include(try=true,priority=1,duplicate=merge) "{{settings.antispam.config_file}}"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
</files>
|
||||
<commands index="3">
|
||||
<command><![CDATA[cp /etc/rspamd/local.d/arc.conf /etc/rspamd/local.d/dkim_signing.conf]]></command>
|
||||
<command><![CDATA[postconf -e "milter_protocol = 6"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_default_action = accept"]]></command>
|
||||
<command><![CDATA[postconf -e "smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[chown -R _rspamd:_rspamd /var/lib/rspamd/dkim]]></command>
|
||||
<command><![CDATA[chmod 440 /var/lib/rspamd/dkim/*]]></command>
|
||||
<command><![CDATA[service rspamd restart]]></command>
|
||||
</commands>
|
||||
</general>
|
||||
<!-- rspamd -->
|
||||
<daemon name="rspamd" title="Rspamd" default="true">
|
||||
<include>//service[@type='antispam']/general/commands[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/installs[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=2]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/files[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=3]
|
||||
</include>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- FTP services -->
|
||||
<service type="ftp" title="{{lng.admin.configfiles.ftp}}">
|
||||
<!-- Proftpd -->
|
||||
|
@ -1727,12 +1727,9 @@ compatibility_level = 2
|
||||
## General Postfix configuration
|
||||
# should be the default domain from your provider eg. "server100.provider.tld"
|
||||
mydomain = <SERVERNAME>
|
||||
|
||||
# should be different from $mydomain eg. "mail.$mydomain"
|
||||
myhostname = mail.$mydomain
|
||||
myhostname = $mydomain
|
||||
|
||||
mydestination = $myhostname,
|
||||
$mydomain,
|
||||
localhost.$myhostname,
|
||||
localhost.$mydomain,
|
||||
localhost
|
||||
@ -2218,6 +2215,98 @@ plugin {
|
||||
<command><![CDATA[/etc/init.d/dovecot restart]]></command>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- Antispam services -->
|
||||
<service type="antispam" title="Antispam">
|
||||
<!-- general RSpamd commands -->
|
||||
<general>
|
||||
<installs index="1">
|
||||
<install><![CDATA[emerge mail-filter/rspamd]]></install>
|
||||
</installs>
|
||||
<commands index="2">
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/local.d/]]></command>
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/override.d/]]></command>
|
||||
<command><![CDATA[mkdir -p mkdir /var/lib/rspamd/dkim/]]></command>
|
||||
</commands>
|
||||
<files index="1">
|
||||
<file name="/etc/rspamd/local.d/actions.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
# Set rewrite subject to this value (%s is replaced by the original subject)
|
||||
subject = "***SPAM*** %s"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/arc.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
try_fallback = true;
|
||||
### Enable DKIM signing for alias sender addresses
|
||||
allow_username_mismatch = true;
|
||||
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
|
||||
selector_map = "/etc/rspamd/dkim_selectors.map";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/milter_headers.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
use = ["x-spamd-bar", "x-spam-level", "authentication-results"];
|
||||
authenticated_headers = ["authentication-results"];
|
||||
extended_spam_headers = true
|
||||
skip_local = false
|
||||
skip_authenticated = false
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/replies.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
## If a user has replied to an email, don’t mark other emails in the same thread as spam
|
||||
action = "no action";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/settings.conf"
|
||||
chown="root:root" chmod="0644" backup="true">
|
||||
<content><![CDATA[
|
||||
## Feel free to include your own settings or adjustments here, for example:
|
||||
#whitelist {
|
||||
# priority = low;
|
||||
# rcpt = "postmaster@example.com";
|
||||
# want_spam = yes;
|
||||
#}
|
||||
|
||||
## Include froxlor generated settings
|
||||
.include(try=true,priority=1,duplicate=merge) "{{settings.antispam.config_file}}"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
</files>
|
||||
<commands index="3">
|
||||
<command><![CDATA[cp /etc/rspamd/local.d/arc.conf /etc/rspamd/local.d/dkim_signing.conf]]></command>
|
||||
<command><![CDATA[postconf -e "milter_protocol = 6"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_default_action = accept"]]></command>
|
||||
<command><![CDATA[postconf -e "smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[chown -R _rspamd:_rspamd /var/lib/rspamd/dkim]]></command>
|
||||
<command><![CDATA[chmod 440 /var/lib/rspamd/dkim/*]]></command>
|
||||
<command><![CDATA[rc-update add rspamd default]]></command>
|
||||
<command><![CDATA[/etc/init.d/rspamd restart]]></command>
|
||||
</commands>
|
||||
</general>
|
||||
<!-- rspamd -->
|
||||
<daemon name="rspamd" title="Rspamd" default="true">
|
||||
<include>//service[@type='antispam']/general/installs[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=2]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/files[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=3]
|
||||
</include>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- FTP services -->
|
||||
<service type="ftp" title="{{lng.admin.configfiles.ftp}}">
|
||||
<!-- Proftpd -->
|
||||
|
@ -1642,7 +1642,7 @@ compatibility_level = 2
|
||||
# for the case of a subdomain, $mydomain *must* be equal to $myhostname,
|
||||
# otherwise you cannot use the main domain for virtual transport.
|
||||
# also check the note about $mydomain below.
|
||||
myhostname = mail.$mydomain
|
||||
myhostname = $mydomain
|
||||
#myhostname = virtual.domain.tld
|
||||
|
||||
# The mydomain parameter specifies the local internet domain name.
|
||||
@ -1656,8 +1656,8 @@ myhostname = mail.$mydomain
|
||||
# FQDN from Froxlor
|
||||
mydomain = <SERVERNAME>
|
||||
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost
|
||||
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
|
||||
mydestination = $myhostname, localhost.$mydomain, localhost
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
|
||||
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
|
||||
# mail.$mydomain, www.$mydomain, ftp.$mydomain
|
||||
|
||||
@ -3344,6 +3344,106 @@ plugin {
|
||||
</include>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- Antispam services -->
|
||||
<service type="antispam" title="Antispam">
|
||||
<!-- general RSpamd commands -->
|
||||
<general>
|
||||
<commands index="1">
|
||||
<command><![CDATA[mkdir -p /etc/apt/keyrings]]></command>
|
||||
<command><![CDATA[wget -O- https://rspamd.com/apt-stable/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/rspamd.gpg > /dev/null]]></command>
|
||||
<command><![CDATA[echo "deb [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ jammy main" > /etc/apt/sources.list.d/rspamd.list]]></command>
|
||||
<command><![CDATA[echo "deb-src [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ jammy main" >> /etc/apt/sources.list.d/rspamd.list]]></command>
|
||||
<command><![CDATA[apt-get update]]></command>
|
||||
</commands>
|
||||
<installs index="1">
|
||||
<install><![CDATA[DEBIAN_FRONTEND=noninteractive apt-get -yq --no-install-recommends install rspamd]]></install>
|
||||
</installs>
|
||||
<commands index="2">
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/local.d/]]></command>
|
||||
<command><![CDATA[mkdir -p /etc/rspamd/override.d/]]></command>
|
||||
<command><![CDATA[mkdir -p mkdir /var/lib/rspamd/dkim/]]></command>
|
||||
</commands>
|
||||
<files index="1">
|
||||
<file name="/etc/rspamd/local.d/actions.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
# Set rewrite subject to this value (%s is replaced by the original subject)
|
||||
subject = "***SPAM*** %s"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/arc.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
try_fallback = true;
|
||||
### Enable DKIM signing for alias sender addresses
|
||||
allow_username_mismatch = true;
|
||||
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
|
||||
selector_map = "/etc/rspamd/dkim_selectors.map";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/milter_headers.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
use = ["x-spamd-bar", "x-spam-level", "authentication-results"];
|
||||
authenticated_headers = ["authentication-results"];
|
||||
extended_spam_headers = true
|
||||
skip_local = false
|
||||
skip_authenticated = false
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/replies.conf"
|
||||
chown="root:root" chmod="0644">
|
||||
<content><![CDATA[
|
||||
## If a user has replied to an email, don’t mark other emails in the same thread as spam
|
||||
action = "no action";
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
<file name="/etc/rspamd/local.d/settings.conf"
|
||||
chown="root:root" chmod="0644" backup="true">
|
||||
<content><![CDATA[
|
||||
## Feel free to include your own settings or adjustments here, for example:
|
||||
#whitelist {
|
||||
# priority = low;
|
||||
# rcpt = "postmaster@example.com";
|
||||
# want_spam = yes;
|
||||
#}
|
||||
|
||||
## Include froxlor generated settings
|
||||
.include(try=true,priority=1,duplicate=merge) "{{settings.antispam.config_file}}"
|
||||
]]>
|
||||
</content>
|
||||
</file>
|
||||
</files>
|
||||
<commands index="3">
|
||||
<command><![CDATA[cp /etc/rspamd/local.d/arc.conf /etc/rspamd/local.d/dkim_signing.conf]]></command>
|
||||
<command><![CDATA[postconf -e "milter_protocol = 6"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}"]]></command>
|
||||
<command><![CDATA[postconf -e "milter_default_action = accept"]]></command>
|
||||
<command><![CDATA[postconf -e "smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"]]></command>
|
||||
<command><![CDATA[chown -R _rspamd:_rspamd /var/lib/rspamd/dkim]]></command>
|
||||
<command><![CDATA[chmod 440 /var/lib/rspamd/dkim/*]]></command>
|
||||
<command><![CDATA[service rspamd restart]]></command>
|
||||
</commands>
|
||||
</general>
|
||||
<!-- rspamd -->
|
||||
<daemon name="rspamd" title="Rspamd" default="true">
|
||||
<include>//service[@type='antispam']/general/commands[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/installs[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=2]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/files[@index=1]
|
||||
</include>
|
||||
<include>//service[@type='antispam']/general/commands[@index=3]
|
||||
</include>
|
||||
</daemon>
|
||||
</service>
|
||||
<!-- FTP services -->
|
||||
<service type="ftp" title="{{lng.admin.configfiles.ftp}}">
|
||||
<!-- Proftpd -->
|
||||
|
@ -111,7 +111,7 @@ return [
|
||||
'selected' => 0
|
||||
],
|
||||
'dkim' => [
|
||||
'visible' => Settings::Get('dkim.use_dkim') == '1',
|
||||
'visible' => Settings::Get('antispam.activated') == '1',
|
||||
'label' => 'DomainKeys',
|
||||
'type' => 'checkbox',
|
||||
'value' => '1',
|
||||
|
@ -129,7 +129,7 @@ return [
|
||||
'selected' => $result['subcanemaildomain']
|
||||
],
|
||||
'dkim' => [
|
||||
'visible' => Settings::Get('dkim.use_dkim') == '1',
|
||||
'visible' => Settings::Get('antispam.activated') == '1',
|
||||
'label' => 'DomainKeys',
|
||||
'type' => 'checkbox',
|
||||
'value' => '1',
|
||||
|
@ -116,6 +116,12 @@ return [
|
||||
'type' => 'hidden',
|
||||
'value' => '0'
|
||||
],
|
||||
'dkim_entry' => [
|
||||
'visible' => (Settings::Get('system.bind_enable') == '0' && Settings::Get('antispam.activated') == '1' && $result['dkim'] == '1' && $result['dkim_pubkey'] != ''),
|
||||
'label' => lng('antispam.required_dkim_dns'),
|
||||
'type' => 'longtext',
|
||||
'value' => (string)(new \Froxlor\Dns\DnsEntry('dkim' . $result['dkim_id'] . '._domainkey', 'TXT', '"v=DKIM1; k=rsa; p='.trim($result['dkim_pubkey']).'"'))
|
||||
],
|
||||
]
|
||||
],
|
||||
'section_bssl' => [
|
||||
|
@ -102,6 +102,44 @@ return [
|
||||
]
|
||||
]
|
||||
],
|
||||
'spam_tag_level' => [
|
||||
'label' => lng('antispam.spam_tag_level'),
|
||||
'type' => 'text',
|
||||
'string_regexp' => '/^\d{1,}(\.\d{1,2})?$/',
|
||||
'value' => $result['spam_tag_level']
|
||||
],
|
||||
'spam_kill_level' => [
|
||||
'label' => lng('antispam.spam_kill_level'),
|
||||
'type' => 'text',
|
||||
'string_regexp' => '/^\d{1,}(\.\d{1,2})?$/',
|
||||
'value' => $result['spam_kill_level']
|
||||
],
|
||||
'bypass_spam' => [
|
||||
'label' => lng('antispam.bypass_spam'),
|
||||
'type' => 'label',
|
||||
'value' => ((int)$result['bypass_spam'] == 0 ? lng('panel.no') : lng('panel.yes')),
|
||||
'next_to' => [
|
||||
'add_link' => [
|
||||
'type' => 'link',
|
||||
'href' => $filename . '?page=' . $page . '&domainid=' . $result['domainid'] . '&action=togglebypass&id=' . $result['id'],
|
||||
'label' => '<i class="fa-solid fa-arrow-right-arrow-left"></i> ' . lng('panel.toggle'),
|
||||
'classes' => 'btn btn-sm btn-secondary'
|
||||
]
|
||||
]
|
||||
],
|
||||
'policy_greylist' => [
|
||||
'label' => lng('antispam.policy_greylist'),
|
||||
'type' => 'label',
|
||||
'value' => ((int)$result['policy_greylist'] == 0 ? lng('panel.no') : lng('panel.yes')),
|
||||
'next_to' => [
|
||||
'add_link' => [
|
||||
'type' => 'link',
|
||||
'href' => $filename . '?page=' . $page . '&domainid=' . $result['domainid'] . '&action=togglegreylist&id=' . $result['id'],
|
||||
'label' => '<i class="fa-solid fa-arrow-right-arrow-left"></i> ' . lng('panel.toggle'),
|
||||
'classes' => 'btn btn-sm btn-secondary'
|
||||
]
|
||||
]
|
||||
],
|
||||
'mail_fwds' => [
|
||||
'label' => lng('emails.forwarders') . ' (' . $forwarders_count . ')',
|
||||
'type' => 'itemlist',
|
||||
@ -119,7 +157,9 @@ return [
|
||||
]
|
||||
],
|
||||
'buttons' => [
|
||||
/* none */
|
||||
[
|
||||
'label' => lng('panel.save')
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
@ -50,7 +50,7 @@ return [
|
||||
'label' => lng('domains.domainname'),
|
||||
'field' => 'domain_ace',
|
||||
'isdefaultsearchfield' => true,
|
||||
'callback' => [Domain::class, 'domainLink'],
|
||||
'callback' => [Domain::class, 'domainEditLink'],
|
||||
],
|
||||
'ipsandports' => [
|
||||
'label' => lng('admin.ipsandports.ipsandports'),
|
||||
|
@ -49,6 +49,24 @@ return [
|
||||
'field' => 'popaccountid',
|
||||
'callback' => [Email::class, 'account'],
|
||||
],
|
||||
'm.spam_tag_level' => [
|
||||
'label' => lng('emails.spam_tag_level'),
|
||||
'field' => 'spam_tag_level',
|
||||
],
|
||||
'm.spam_kill_level' => [
|
||||
'label' => lng('emails.spam_kill_level'),
|
||||
'field' => 'spam_kill_level',
|
||||
],
|
||||
'm.bypass_spam' => [
|
||||
'label' => lng('emails.bypass_spam'),
|
||||
'field' => 'bypass_spam',
|
||||
'callback' => [Text::class, 'boolean'],
|
||||
],
|
||||
'm.policy_greylist' => [
|
||||
'label' => lng('emails.policy_greylist'),
|
||||
'field' => 'policy_greylist',
|
||||
'callback' => [Text::class, 'boolean'],
|
||||
],
|
||||
'm.iscatchall' => [
|
||||
'label' => lng('emails.catchall'),
|
||||
'field' => 'iscatchall',
|
||||
|
@ -629,45 +629,6 @@ return [
|
||||
'mysqlserver' => 'Servidor mysql utilitzable'
|
||||
],
|
||||
'diskquota' => 'Quota',
|
||||
'dkim' => [
|
||||
'dkim_prefix' => [
|
||||
'title' => 'Prefix',
|
||||
'description' => 'Especifiqueu la ruta als fitxers DKIM RSA i als fitxers de configuració del plugin Milter'
|
||||
],
|
||||
'dkim_domains' => [
|
||||
'title' => 'Nom del fitxer dels dominis',
|
||||
'description' => '<em>Nom de fitxer</em> del paràmetre DKIM Domains especificat a la configuració dkim-milter'
|
||||
],
|
||||
'dkim_dkimkeys' => [
|
||||
'title' => 'Nom de l\'arxiu KeyList',
|
||||
'description' => '<em>Nom de fitxer</em> del paràmetre DKIM KeyList especificat a la configuració de dkim-milter'
|
||||
],
|
||||
'dkimrestart_command' => [
|
||||
'title' => 'Ordre de reinici del filtre',
|
||||
'description' => 'Especifiqui l\'ordre de reinici del servei DKIM milter'
|
||||
],
|
||||
'privkeysuffix' => [
|
||||
'title' => 'Sufix de claus privades',
|
||||
'description' => 'Pot especificar una extensió/sufix de nom de fitxer (opcional) per a les claus privades dkim generades. Alguns serveis com dkim-filter requereixen que estigui buit.'
|
||||
],
|
||||
'use_dkim' => [
|
||||
'title' => 'Activar suport DKIM?',
|
||||
'description' => 'Voleu utilitzar el sistema de claus de domini (DKIM)?<br/><em class="text-danger">Nota: DKIM només és compatible amb dkim-filter, no amb opendkim (de moment)</em>'
|
||||
],
|
||||
'dkim_algorithm' => [
|
||||
'title' => 'Algorismes Hash permesos',
|
||||
'description' => 'Defineix els algorismes hash permesos, escull "Tots" per a tots els algorismes o un o més dels altres algorismes disponibles'
|
||||
],
|
||||
'dkim_servicetype' => 'Tipus de servei',
|
||||
'dkim_keylength' => [
|
||||
'title' => 'Longitud de clau',
|
||||
'description' => 'Atenció: Si canvia aquests valors, haurà d\'eliminar totes les claus privades/públiques de "%s".'
|
||||
],
|
||||
'dkim_notes' => [
|
||||
'title' => 'Notes DKIM',
|
||||
'description' => 'Notes que podrien ser d\'interès per a un humà, per exemple, una URL com http://www.dnswatch.info. Cap programa no realitza cap interpretació. Aquesta etiqueta s\'ha de fer servir amb moderació a causa de les limitacions d\'espai al DNS. Està pensada perquè la facin servir els administradors, no els usuaris finals.'
|
||||
]
|
||||
],
|
||||
'dns' => [
|
||||
'destinationip' => 'IP(s) del domini',
|
||||
'standardip' => 'IP estàndard del servidor',
|
||||
|
@ -264,7 +264,7 @@ return [
|
||||
'text' => 'Nachricht',
|
||||
'sslsettings' => 'SSL-Einstellungen',
|
||||
'specialsettings_replacements' => 'Die folgenden Variablen können verwendet werden:<br/><code>{DOMAIN}</code>, <code>{DOCROOT}</code>, <code>{CUSTOMER}</code>, <code>{IP}</code>, <code>{PORT}</code>, <code>{SCHEME}</code>, <code>{FPMSOCKET}</code> (wenn zutreffend)<br/>',
|
||||
'dkimsettings' => 'DomainKey-Einstellungen',
|
||||
'antispam_settings' => 'Antispam-Einstellungen',
|
||||
'caneditphpsettings' => 'Kann PHP-bezogene Domaineinstellungen vornehmen?',
|
||||
'allips' => 'Alle IP-Adressen',
|
||||
'awstatssettings' => 'AWstats-Einstellungen',
|
||||
@ -595,43 +595,38 @@ return [
|
||||
'mysqlserver' => 'Erlaubte MySQL-Server',
|
||||
],
|
||||
'diskquota' => 'Quota',
|
||||
'dkim' => [
|
||||
'dkim_prefix' => [
|
||||
'title' => 'Prefix',
|
||||
'description' => 'Wie lautet der Pfad zu den DKIM-RSA-Dateien sowie den Einstellungsdateien des Milter-Plugins?',
|
||||
'antispam' => [
|
||||
'config_file' => [
|
||||
'title' => 'Antispam Konfigurationsdatei',
|
||||
'description' => 'Pfad + Dateiname der Antispam-Regel Konfigurationsdatei',
|
||||
],
|
||||
'dkim_domains' => [
|
||||
'title' => 'Domains-Dateiname',
|
||||
'description' => 'Dateiname der DKIM-Domains-Angabe aus der DKIM-Milter-Konfigurationsdatei.',
|
||||
'reload_command' => [
|
||||
'title' => 'Milter-Restart-Befehl',
|
||||
'description' => 'Wie lautet der Befehl zum Neustarten des rspamd-Dienstes?',
|
||||
],
|
||||
'dkim_dkimkeys' => [
|
||||
'title' => 'KeyList Dateiname',
|
||||
'description' => 'Dateiname der DKIM-KeyList-Angabe aus der DKIM-Milter-Konfigurationsdatei.',
|
||||
'activated' => [
|
||||
'title' => 'Antispam aktivieren?',
|
||||
'description' => 'Aktivieren, um rspamd als Antispam Dienst zu verwenden.',
|
||||
],
|
||||
'dkimrestart_command' => [
|
||||
'title' => 'Milter-Restart-Kommando',
|
||||
'description' => 'Wie lautet das Kommando zum Neustarten des DKIM-Milter-Dienstes?',
|
||||
],
|
||||
'privkeysuffix' => [
|
||||
'title' => 'Suffix für Private Keys',
|
||||
'description' => 'Hier kann eine (optionale) Dateiendung für die generierten Private Keys angegeben werden. Manche Dienste, wie dkim-filter, erwarten, dass die Schlüssel keine Dateiendung haben (leer).',
|
||||
],
|
||||
'use_dkim' => [
|
||||
'title' => 'DKIM-Support aktivieren?',
|
||||
'description' => 'Wollen Sie das Domain-Keys-System (DKIM) benutzen?<br/><em class="text-danger">Hinweis: Derzeit wird DKIM nur via dkim-filter unterstützt, nicht opendkim.</em>',
|
||||
],
|
||||
'dkim_algorithm' => [
|
||||
'title' => 'Gültige Hash-Algorithmen',
|
||||
'description' => 'Wählen Sie einen Algorithmus, "All" für alle Algorithmen oder einen oder mehrere von den verfügbaren Algorithmen.',
|
||||
],
|
||||
'dkim_servicetype' => 'Service Typen',
|
||||
'dkim_keylength' => [
|
||||
'title' => 'Schlüssel-Länge',
|
||||
'description' => 'Achtung: Bei Änderung dieser Einstellung müssen alle private/public Schlüssel in "%s" gelöscht werden.',
|
||||
'title' => 'DKIM Schlüssel-Länge',
|
||||
'description' => 'Achtung: Änderungen sind nur für neue Schlüssel gültig.<br/><br/>Erfordert einen speziellen DNS Eintrag für die Domain. Wenn das Nameserver-Feature nicht genutzt wird, muss dieser Eintrag manuell verwaltet werden.',
|
||||
],
|
||||
'dkim_notes' => [
|
||||
'title' => 'DKIM Notiz',
|
||||
'description' => 'Eine Notiz, welche für Menschen interessant sein könnte, z.B. eine URL wie http://www.dnswatch.info. Es gibt keine programmgesteuerte Interpretation für dieses Feld. Gehen Sie sparsam mit der Anzahl der Zeichen um, da es Einschränkungen seitens des DNS-Dienstes gibt. Dieses Feld ist für Administratoren gedacht, nicht für Benutzer.',
|
||||
'spam_tag_level' => [
|
||||
'title' => 'Spam Markierungs-Level',
|
||||
'description' => 'Erforderliche Punktzahl zum Markieren einer E-Mail als Spam<br/>Standard: 7.0'
|
||||
],
|
||||
'spam_kill_level' => [
|
||||
'title' => 'Spam Ignorier-Level',
|
||||
'description' => 'Erforderliche Punktzahl für das Ablehnen einer E-Mail<br/>Standard: 14.0'
|
||||
],
|
||||
'bypass_spam' => [
|
||||
'title' => 'Spamfilter umgehen',
|
||||
'description' => 'Aktivieren, um den Spamfilter für diese Adresse zu umgehen/deaktivieren.<br/>Standard: Nein'
|
||||
],
|
||||
'policy_greylist' => [
|
||||
'title' => 'Verwende greylisting',
|
||||
'description' => 'Eingehende E-Mails mittels <a href="https://de.wikipedia.org/wiki/Greylisting" target="_blank">Greylisting</a> schützen.<br/>Standard: Ja'
|
||||
],
|
||||
],
|
||||
'dns' => [
|
||||
@ -2108,9 +2103,19 @@ Vielen Dank, Ihr Administrator',
|
||||
],
|
||||
],
|
||||
'spf' => [
|
||||
'use_spf' => 'Aktiviere SPF für Domains?',
|
||||
'use_spf' => [
|
||||
'title' => 'Aktiviere SPF für Domains?',
|
||||
'description' => 'Erfordert einen speziellen DNS Eintrag für die Domain. Wenn das Nameserver-Feature nicht genutzt wird, muss dieser Eintrag manuell verwaltet werden.',
|
||||
],
|
||||
'spf_entry' => 'SPF-Eintrag für alle Domains',
|
||||
],
|
||||
'dmarc' => [
|
||||
'use_dmarc' => [
|
||||
'title' => 'Aktiviere DMARC für Domains?',
|
||||
'description' => 'Erfordert einen speziellen DNS Eintrag für die Domain. Wenn das Nameserver-Feature nicht genutzt wird, muss dieser Eintrag manuell verwaltet werden.',
|
||||
],
|
||||
'dmarc_entry' => 'DMARC-Eintrag für alle Domains',
|
||||
],
|
||||
'success' => [
|
||||
'messages_success' => 'Nachricht erfolgreich an "%s" Empfänger gesendet',
|
||||
'success' => 'Information',
|
||||
|
@ -268,7 +268,7 @@ return [
|
||||
'text' => 'Message',
|
||||
'sslsettings' => 'SSL settings',
|
||||
'specialsettings_replacements' => 'You can use the following variables:<br/><code>{DOMAIN}</code>, <code>{DOCROOT}</code>, <code>{CUSTOMER}</code>, <code>{IP}</code>, <code>{PORT}</code>, <code>{SCHEME}</code>, <code>{FPMSOCKET}</code> (if applicable)<br/>',
|
||||
'dkimsettings' => 'DomainKey settings',
|
||||
'antispam_settings' => 'Antispam settings',
|
||||
'caneditphpsettings' => 'Can change php-related domain settings?',
|
||||
'allips' => 'All IP\'s',
|
||||
'awstatssettings' => 'AWstats settings',
|
||||
@ -644,43 +644,38 @@ return [
|
||||
'mysqlserver' => 'Usable mysql-server',
|
||||
],
|
||||
'diskquota' => 'Quota',
|
||||
'dkim' => [
|
||||
'dkim_prefix' => [
|
||||
'title' => 'Prefix',
|
||||
'description' => 'Please specify the path to the DKIM RSA-files as well as to the configuration files for the Milter-plugin',
|
||||
'antispam' => [
|
||||
'config_file' => [
|
||||
'title' => 'Antispam settings file',
|
||||
'description' => 'Please specify the filename for the email-antispam rules',
|
||||
],
|
||||
'dkim_domains' => [
|
||||
'title' => 'Domains filename',
|
||||
'description' => '<em>Filename</em> of the DKIM Domains parameter specified in the dkim-milter configuration',
|
||||
],
|
||||
'dkim_dkimkeys' => [
|
||||
'title' => 'KeyList filename',
|
||||
'description' => '<em>Filename</em> of the DKIM KeyList parameter specified in the dkim-milter configuration',
|
||||
],
|
||||
'dkimrestart_command' => [
|
||||
'reload_command' => [
|
||||
'title' => 'Milter restart command',
|
||||
'description' => 'Please specify the restart command for the DKIM milter service',
|
||||
'description' => 'Please specify the restart command for the rspamd service',
|
||||
],
|
||||
'privkeysuffix' => [
|
||||
'title' => 'Private keys suffix',
|
||||
'description' => 'You can specify an (optional) filename extension/suffix for the generate dkim private keys. Some services like dkim-filter requires this to be empty',
|
||||
'activated' => [
|
||||
'title' => 'Activate antispam?',
|
||||
'description' => 'Would you like to use rspamd as antispam service?',
|
||||
],
|
||||
'use_dkim' => [
|
||||
'title' => 'Activate DKIM support?',
|
||||
'description' => 'Would you like to use the Domain Keys (DKIM) system?<br/><em class="text-danger">Note: DKIM is only supported using dkim-filter, not opendkim (yet)</em>',
|
||||
],
|
||||
'dkim_algorithm' => [
|
||||
'title' => 'Allowed Hash Algorithms',
|
||||
'description' => 'Define allowed hash algorithms, chose "All" for all algorithms or one or more from the other available algorithms',
|
||||
],
|
||||
'dkim_servicetype' => 'Service Types',
|
||||
'dkim_keylength' => [
|
||||
'title' => 'Key-length',
|
||||
'description' => 'Attention: If you change this values, you need to delete all the private/public keys in "%s"',
|
||||
'title' => 'DKIM Key-length',
|
||||
'description' => 'Attention: Changes will only apply for new keys<br/><br/>Requires a specific dns entry for the domain. If you are not using the nameserver feature, you will have to manually manage these entries.',
|
||||
],
|
||||
'dkim_notes' => [
|
||||
'title' => 'DKIM Notes',
|
||||
'description' => 'Notes that might be of interest to a human, e.g. a URL like http://www.dnswatch.info. No interpretation is made by any program. This tag should be used sparingly due to space limitations in DNS. This is intended for use by administrators, not end users.',
|
||||
'spam_tag_level' => [
|
||||
'title' => 'Spam tag level',
|
||||
'description' => 'Score that is required to mark an email as spam<br/>Default: 7.0'
|
||||
],
|
||||
'spam_kill_level' => [
|
||||
'title' => 'Spam kill level',
|
||||
'description' => 'Score that is required to discard an email entirely<br/>Default: 14.0'
|
||||
],
|
||||
'bypass_spam' => [
|
||||
'title' => 'Bypass spamfilter',
|
||||
'description' => 'Activate to bypass/disable spamfiltering for this address.<br/>Default: no'
|
||||
],
|
||||
'policy_greylist' => [
|
||||
'title' => 'Use greylisting',
|
||||
'description' => 'Incoming emails will be protected by <a href="https://en.wikipedia.org/wiki/Greylisting_(email)" target="_blank">greylisting</a>.<br/>Default: yes'
|
||||
],
|
||||
],
|
||||
'dns' => [
|
||||
@ -2236,9 +2231,19 @@ Yours sincerely, your administrator',
|
||||
],
|
||||
],
|
||||
'spf' => [
|
||||
'use_spf' => 'Activate SPF for domains?',
|
||||
'use_spf' => [
|
||||
'title' => 'Activate SPF for domains?',
|
||||
'description' => 'Requires a specific dns entry for the domain. If you are not using the nameserver feature, you will have to manually manage these entries.',
|
||||
],
|
||||
'spf_entry' => 'SPF entry for all domains',
|
||||
],
|
||||
'dmarc' => [
|
||||
'use_dmarc' => [
|
||||
'title' => 'Activate DMARC for domains?',
|
||||
'description' => 'Requires a specific dns entry for the domain. If you are not using the nameserver feature, you will have to manually manage these entries.',
|
||||
],
|
||||
'dmarc_entry' => 'DMARC entry for all domains',
|
||||
],
|
||||
'ssl_certificates' => [
|
||||
'certificate_for' => 'Certificate for',
|
||||
'valid_from' => 'Valid from',
|
||||
|
@ -628,45 +628,6 @@ return [
|
||||
'mysqlserver' => 'Servidor mysql utilizable'
|
||||
],
|
||||
'diskquota' => 'Cuota',
|
||||
'dkim' => [
|
||||
'dkim_prefix' => [
|
||||
'title' => 'Prefijo',
|
||||
'description' => 'Especifique la ruta a los archivos DKIM RSA y a los archivos de configuración del plugin Milter'
|
||||
],
|
||||
'dkim_domains' => [
|
||||
'title' => 'Nombre de archivo de los dominios',
|
||||
'description' => '<em>Nombre de</em> archivo del parámetro DKIM Domains especificado en la configuración de dkim-milter'
|
||||
],
|
||||
'dkim_dkimkeys' => [
|
||||
'title' => 'KeyList filename',
|
||||
'description' => '<em>Nombre</em> de archivo del parámetro DKIM KeyList especificado en la configuración de dkim-milter'
|
||||
],
|
||||
'dkimrestart_command' => [
|
||||
'title' => 'Comando de reinicio del filtro',
|
||||
'description' => 'Especifique el comando de reinicio del servicio DKIM milter'
|
||||
],
|
||||
'privkeysuffix' => [
|
||||
'title' => 'Sufijo de claves privadas',
|
||||
'description' => 'Puede especificar una extensión/sufijo de nombre de archivo (opcional) para las claves privadas dkim generadas. Algunos servicios como dkim-filter requieren que esté vacío.'
|
||||
],
|
||||
'use_dkim' => [
|
||||
'title' => '¿Activar soporte DKIM?',
|
||||
'description' => '¿Desea utilizar el sistema de claves de dominio (DKIM)?<br/><em class="text-danger">Nota: DKIM sólo es compatible con dkim-filter, no con opendkim (todavía)</em>'
|
||||
],
|
||||
'dkim_algorithm' => [
|
||||
'title' => 'Algoritmos Hash permitidos',
|
||||
'description' => 'Defina los algoritmos hash permitidos, elija "Todos" para todos los algoritmos o uno o más de los otros algoritmos disponibles'
|
||||
],
|
||||
'dkim_servicetype' => 'Tipos de servicio',
|
||||
'dkim_keylength' => [
|
||||
'title' => 'Longitud de clave',
|
||||
'description' => 'Atención: Si cambia estos valores, deberá eliminar todas las claves privadas/públicas de "%s".'
|
||||
],
|
||||
'dkim_notes' => [
|
||||
'title' => 'Notas DKIM',
|
||||
'description' => 'Notas que podrían ser de interés para un humano, por ejemplo, una URL como http://www.dnswatch.info. Ningún programa realiza ninguna interpretación. Esta etiqueta debe utilizarse con moderación debido a las limitaciones de espacio en DNS. Está pensada para que la utilicen los administradores, no los usuarios finales.'
|
||||
]
|
||||
],
|
||||
'dns' => [
|
||||
'destinationip' => 'IP(s) del dominio',
|
||||
'standardip' => 'IP estándar del servidor',
|
||||
|
@ -660,41 +660,6 @@ return [
|
||||
'services' => 'Servizi',
|
||||
],
|
||||
'diskquota' => 'Quota',
|
||||
'dkim' => [
|
||||
'dkim_prefix' => [
|
||||
'title' => 'Prefisso',
|
||||
'description' => 'Si prega di specificare il percorso della DKIM RSA-files, nonch¸ i file di configurazione per il plugin Milter',
|
||||
],
|
||||
'dkim_domains' => [
|
||||
'title' => 'Domini nomefile',
|
||||
'description' => '<em>Nome file</em> del parametro DKIM Domains specificata nella configurazione dkim-milter',
|
||||
],
|
||||
'dkim_dkimkeys' => [
|
||||
'title' => 'Nome file del KeyList',
|
||||
'description' => '<em>Nome file</em> del parametro DKIM KeyList specificata nella configurazione dkim-milter',
|
||||
],
|
||||
'dkimrestart_command' => [
|
||||
'title' => 'Milter commando riavvio',
|
||||
'description' => 'Si prega di specificare il comando per riavviare il servizio DKIM milter',
|
||||
],
|
||||
'use_dkim' => [
|
||||
'title' => 'Attivare il supporto DKIM?',
|
||||
'description' => 'Vuoi utilizzare il sistema Domain Keys (DKIM)?',
|
||||
],
|
||||
'dkim_algorithm' => [
|
||||
'title' => 'Ammessi Algoritmi Hash',
|
||||
'description' => 'Definire gli algoritmi di hash permessi, scegliere "Tutti" per permettere tutti gli algoritmi oppure uno o più tra gli altri algoritmi disponibili',
|
||||
],
|
||||
'dkim_servicetype' => 'Tipi di Servizio',
|
||||
'dkim_keylength' => [
|
||||
'title' => 'Lunghezza Chiave',
|
||||
'description' => 'Attenzione: Se si modifica questo valore è necessario eliminare tutte le chiavi private/pubbliche in "%s"',
|
||||
],
|
||||
'dkim_notes' => [
|
||||
'title' => 'Note DKIM',
|
||||
'description' => 'Nota potrebbe essere di interesse, es. un URL come http://www.dnswatch.info. Nessuna interpretazione è fatta da nessun programma. Questo tag deve essere usato con parsimonia per ragioni di spazio nel DNS. Questo è destinato ad essere utilizzato dagli amministratori e non dagli utenti finali.',
|
||||
],
|
||||
],
|
||||
'dns' => [
|
||||
'destinationip' => 'Dominio IP',
|
||||
'a_record' => 'A-Record (IPv6 optionale)',
|
||||
|
@ -328,41 +328,6 @@ return [
|
||||
'mail_quota' => 'Mailquotum',
|
||||
'sendinfomail' => 'Stuur gegevens naar mij via e-mail',
|
||||
],
|
||||
'dkim' => [
|
||||
'dkim_prefix' => [
|
||||
'title' => 'Prefix',
|
||||
'description' => 'Geef het pad naar de DKIM RSA-files alsook naar de configuratie van de Milter-plugin',
|
||||
],
|
||||
'dkim_domains' => [
|
||||
'title' => 'Bestandsnaam domeinen',
|
||||
'description' => '<em>Bestandsnaam</em> van het DKIM Domains-parameter zoals aangegeven in de configuratie van dkim-milter',
|
||||
],
|
||||
'dkim_dkimkeys' => [
|
||||
'title' => 'KeyList filename',
|
||||
'description' => '<em>Bestandsnaam</em> van het DKIM KeyList-parameter zoals aangegeven in de configuratie van dkim-milter',
|
||||
],
|
||||
'dkimrestart_command' => [
|
||||
'title' => 'Herstart-commando voor Milter',
|
||||
'description' => 'Geef het commando om de milter-plugin te herstarten',
|
||||
],
|
||||
'use_dkim' => [
|
||||
'title' => 'Activeer ondersteuning voor DKIM?',
|
||||
'description' => 'Wilt u gebruikmaken van Domain Keys (DKIM) systeem?',
|
||||
],
|
||||
'dkim_algorithm' => [
|
||||
'title' => 'Toegestane hash-algoritmen',
|
||||
'description' => 'Toegestane hash-algoritmen, kies "Alle" voor alle algoritmen of 1 of meerdere van onderstaande',
|
||||
],
|
||||
'dkim_servicetype' => 'Type services',
|
||||
'dkim_keylength' => [
|
||||
'title' => 'Lengte sleutel',
|
||||
'description' => 'Let op: Indien u deze waarde wijzigt, dient u allen geheime en publieke sleutels in "%s" te verwijderen',
|
||||
],
|
||||
'dkim_notes' => [
|
||||
'title' => 'Notities voor DKIM',
|
||||
'description' => 'Notities die van belang kunnen zijn voor mensen, bijvoorbeeld een URL als http://www.dnswatch.info. Geen enkel programma zal deze informatie verwerken. Deze informatie dient schaars te zijn gezien de beperkte ruimte in DNS. Dit is bedoeld voor beheerders, niet voor eindgebruikers.',
|
||||
],
|
||||
],
|
||||
'dns' => [
|
||||
'destinationip' => 'IP domein',
|
||||
'standardip' => 'Standaard server IP',
|
||||
|
3
templates/Froxlor/assets/js/bootstrap.js
vendored
3
templates/Froxlor/assets/js/bootstrap.js
vendored
@ -14,6 +14,9 @@ window.bootstrap = bootstrap;
|
||||
import Chart from 'chart.js/auto';
|
||||
window.Chart = Chart;
|
||||
|
||||
// set a default theme
|
||||
window.$theme = 'Froxlor';
|
||||
|
||||
// Axios
|
||||
import axios from 'axios';
|
||||
window.axios = axios;
|
||||
|
12
templates/Froxlor/assets/js/jquery/global.js
vendored
12
templates/Froxlor/assets/js/jquery/global.js
vendored
@ -8,13 +8,15 @@ export default function () {
|
||||
history.back(1);
|
||||
})
|
||||
|
||||
$('#copySysInfo').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
navigator.clipboard.writeText($('#ccSysInfo').text().trim());
|
||||
})
|
||||
|
||||
$('[data-bs-toggle="popover"]').each(function () {
|
||||
new bootstrap.Popover($(this));
|
||||
})
|
||||
|
||||
$('.copyClipboard').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
const source_element = $(this).data('clipboard-source').text();
|
||||
navigator.clipboard.writeText($('#' + source_element).text().trim());
|
||||
})
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -60,6 +60,8 @@
|
||||
{{ _self.select(id, field) }}
|
||||
{% elseif field.type == 'textarea' %}
|
||||
{{ _self.textarea(id, field) }}
|
||||
{% elseif field.type == 'longtext' %}
|
||||
{{ _self.longtext(id, field) }}
|
||||
{% elseif field.type == 'label' %}
|
||||
{{ _self.plain(id, field) }}
|
||||
{% elseif field.type == 'link' %}
|
||||
@ -155,6 +157,15 @@
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro longtext(id, field) %}
|
||||
<div>
|
||||
<div class="float-end">
|
||||
<button class="btn btn-outline-secondary copyClipboard" data-clipboard-source="{{ id }}" style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .5rem;" title="Copy to clipboard"><i class="fa-solid fa-copy"></i></button>
|
||||
</div>
|
||||
<p class="text-break" id="{{ id }}">{{ field.value|raw }}</p>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro input(id, field) %}
|
||||
{% if field.next_to is defined %}
|
||||
<div class="input-group">
|
||||
|
@ -79,7 +79,8 @@
|
||||
(dtype == 'bind' and get_setting('system.bind_enable') == '1' and get_setting('system.dns_server') == 'Bind') or
|
||||
(dtype == 'powerdns' and get_setting('system.bind_enable') == '1' and get_setting('system.dns_server') == 'PowerDNS') or
|
||||
(dtype == 'proftpd' and get_setting('system.ftpserver') == 'proftpd') or
|
||||
(dtype == 'pureftpd' and get_setting('system.ftpserver') == 'pureftpd')
|
||||
(dtype == 'pureftpd' and get_setting('system.ftpserver') == 'pureftpd') or
|
||||
(dtype == 'rspamd' and get_setting('antispam.activated') == '1')
|
||||
%}
|
||||
{% set recommended = true %}
|
||||
{% endif %}
|
||||
|
@ -67,7 +67,7 @@
|
||||
<i class="fa-solid fa-gears me-1"></i>
|
||||
{{ lng('admin.systemdetails') }}
|
||||
<div class="float-end">
|
||||
<button id="copySysInfo" class="btn btn-outline-secondary" style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .5rem;" title="Copy to clipboard"><i class="fa-solid fa-copy"></i></button>
|
||||
<button id="copySysInfo" class="btn btn-outline-secondary copyClipboard" data-clipboard-source="ccSysInfo" style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .5rem;" title="Copy to clipboard"><i class="fa-solid fa-copy"></i></button>
|
||||
</div>
|
||||
<div id="ccSysInfo" class="d-none">
|
||||
- Froxlor: {{ call_static('\\Froxlor\\Froxlor', 'getVersionString') }}
|
||||
|
@ -20,7 +20,7 @@
|
||||
<nav class="navbar navbar-expand-md navbar-light p-0 {% if not block('heading') %}shadow-sm{% endif %}">
|
||||
<div class="container-fluid gx-0">
|
||||
<div>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#sidebar" aria-controls="sidebar" aria-expanded="false" aria-label="Toggle sidebar">
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#sidebar" aria-controls="sidebar" aria-expanded="false" aria-label="Toggle sidebar">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
</div>
|
||||
@ -51,20 +51,30 @@
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarOpts">
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ linker({'section': 'index', 'page': 'profile'}) }}"><i class="fa-solid fa-user-gear"></i> {{ lng('panel.profile') }}</a>
|
||||
<a class="dropdown-item" href="{{ linker({'section': 'index', 'page': 'profile'}) }}">
|
||||
<i class="fa-solid fa-user-gear"></i> {{ lng('panel.profile') }}
|
||||
</a>
|
||||
</li>
|
||||
{% if get_setting('2fa.enabled') == 1 %}
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ linker({'section': 'index', 'page': '2fa'}) }}"><i class="fa-solid fa-shield"></i> {{ lng('2fa.2fa') }}</a>
|
||||
<a class="dropdown-item" href="{{ linker({'section': 'index', 'page': '2fa'}) }}">
|
||||
<i class="fa-solid fa-shield"></i> {{ lng('2fa.2fa') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if get_setting('api.enabled') == 1 and userinfo.api_allowed == 1 %}
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ linker({'section': 'index', 'page': 'apikeys'}) }}"><i class="fa-solid fa-key"></i> {{ lng('menue.main.apikeys') }}</a>
|
||||
<hr class="dropdown-divider">
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="https://docs.froxlor.org/latest/api-guide/" rel="external" target="_blank"><i class="fa-solid fa-circle-info"></i> {{ lng('menue.main.apihelp') }}</a>
|
||||
<a class="dropdown-item" href="{{ linker({'section': 'index', 'page': 'apikeys'}) }}">
|
||||
<i class="fa-solid fa-key"></i> {{ lng('menue.main.apikeys') }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="https://docs.froxlor.org/latest/api-guide/" rel="external" target="_blank">
|
||||
<i class="fa-solid fa-circle-info"></i> {{ lng('menue.main.apihelp') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
@ -105,6 +115,14 @@
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% block errors %}
|
||||
{% if call_static('\\Froxlor\\ErrorBag', 'hasErrors') %}
|
||||
{% for error in call_static('\\Froxlor\\ErrorBag', 'getErrors') %}
|
||||
{{ error|raw }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
<section class="flex-grow-1 p-3 p-lg-5">
|
||||
{% block content %}{% endblock %}
|
||||
</section>
|
||||
|
Loading…
Reference in New Issue
Block a user