[Web] Sync jobs: Use STARTTLS instead of TLS; Feature: Allow to edit fail2ban-like regex filters in UI
parent
0b0aaf0705
commit
877b9b7054
|
@ -698,6 +698,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
|||
<input type="number" class="form-control" name="netban_ipv6" value="<?=$f2b_data['netban_ipv6'];?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<p class="help-block"><?=$lang['admin']['f2b_list_info'];?></p>
|
||||
<div class="form-group">
|
||||
<label for="whitelist"><?=$lang['admin']['f2b_whitelist'];?>:</label>
|
||||
|
@ -708,11 +709,41 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
|||
<textarea class="form-control" name="blacklist" rows="5"><?=$f2b_data['blacklist'];?></textarea>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-success" data-action="edit_selected" data-item="self" data-id="f2b" data-api-url='edit/fail2ban' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||
<a href="#" role="button" class="btn btn-default" data-toggle="modal" data-container="netfilter-mailcow" data-target="#RestartContainer"><span class="glyphicon glyphicon-refresh"></span> <?= $lang['header']['restart_netfilter']; ?></a>
|
||||
<button class="btn btn-sm btn-success" data-action="edit_selected" data-item="self" data-id="f2b" data-api-url='edit/fail2ban' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||
<a href="#" role="button" class="btn btn-sm btn-default" data-toggle="modal" data-container="netfilter-mailcow" data-target="#RestartContainer"><span class="glyphicon glyphicon-refresh"></span> <?= $lang['header']['restart_netfilter']; ?></a>
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
<h4><?=$lang['admin']['f2b_filter'];?></h4>
|
||||
<p class="help-block"><?=$lang['admin']['f2b_regex_info'];?></p>
|
||||
<form class="form-inline" data-id="f2b_regex" role="form" method="post">
|
||||
<table class="table table-condensed" id="f2b_regex_table">
|
||||
<tr>
|
||||
<th width="50px">ID</th>
|
||||
<th>RegExp</th>
|
||||
<th width="100px"> </th>
|
||||
</tr>
|
||||
<?php
|
||||
if (!empty($f2b_data['regex'])) {
|
||||
foreach ($f2b_data['regex'] as $regex_id => $regex_val) {
|
||||
?>
|
||||
<tr>
|
||||
<td><input disabled class="input-sm form-control" style="text-align:center" data-id="f2b_regex" type="text" name="app" required value="<?=$regex_id;?>"></td>
|
||||
<td><input class="input-sm form-control regex-input" data-id="f2b_regex" type="text" name="regex" required value="<?=htmlspecialchars($regex_val);?>"></td>
|
||||
<td><a href="#" role="button" class="btn btn-xs btn-default" type="button"><?=$lang['admin']['remove_row'];?></a></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
<p><div class="btn-group">
|
||||
<button class="btn btn-sm btn-success" data-action="edit_selected" data-item="admin" data-id="f2b_regex" data-reload="no" data-api-url='edit/fail2ban' data-api-attr='{"action":"edit-regex"}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||
<button class="btn btn-sm btn-default admin-ays-dialog" data-action="edit_selected" data-item="self" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"reset-regex"}' href="#"><?=$lang['admin']['reset_default'];?></button>
|
||||
<button class="btn btn-sm btn-default" type="button" id="add_f2b_regex_row"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add_row'];?></button>
|
||||
</div></p>
|
||||
</form>
|
||||
<hr>
|
||||
<p class="help-block"><?=$lang['admin']['ban_list_info'];?></p>
|
||||
<?php
|
||||
if (empty($f2b_data['active_bans']) && empty($f2b_data['perm_bans'])):
|
||||
|
|
|
@ -72,4 +72,8 @@ table tbody tr td input[type="checkbox"] {
|
|||
}
|
||||
#quarantine_template {
|
||||
margin:20px;
|
||||
}
|
||||
.regex-input {
|
||||
font-family: Consolas,monaco,monospace;
|
||||
font-size: 14px;
|
||||
}
|
|
@ -1234,9 +1234,9 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||
<label class="control-label col-sm-2" for="enc1"><?=$lang['edit']['encryption'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<select id="enc1" name="enc1">
|
||||
<option <?=($result['enc1'] == "TLS") ? "selected" : null;?>>TLS</option>
|
||||
<option <?=($result['enc1'] == "SSL") ? "selected" : null;?>>SSL</option>
|
||||
<option <?=($result['enc1'] == "PLAIN") ? "selected" : null;?>>PLAIN</option>
|
||||
<option value="SSL" <?=($result['enc1'] == "SSL") ? "selected" : null;?>>SSL</option>
|
||||
<option value="TLS" <?=($result['enc1'] == "TLS") ? "selected" : null;?>>STARTTLS</option>
|
||||
<option value="PLAIN" <?=($result['enc1'] == "PLAIN") ? "selected" : null;?>>PLAIN</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -10,6 +10,7 @@ function fail2ban($_action, $_data = null) {
|
|||
}
|
||||
try {
|
||||
$f2b_options = json_decode($redis->Get('F2B_OPTIONS'), true);
|
||||
$f2b_options['regex'] = json_decode($redis->Get('F2B_REGEX'), true);
|
||||
$wl = $redis->hGetAll('F2B_WHITELIST');
|
||||
if (is_array($wl)) {
|
||||
foreach ($wl as $key => $value) {
|
||||
|
@ -87,20 +88,101 @@ function fail2ban($_action, $_data = null) {
|
|||
);
|
||||
return false;
|
||||
}
|
||||
if (isset($_data['action']) && !empty($_data['network'])) {
|
||||
$networks = (array) $_data['network'];
|
||||
foreach ($networks as $network) {
|
||||
// Start to read actions, if any
|
||||
if (isset($_data['action'])) {
|
||||
// Reset regex filters
|
||||
if ($_data['action'] == "reset-regex") {
|
||||
try {
|
||||
$redis->Del('F2B_REGEX');
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
// Rules will also be recreated on log events, but rules may seem empty for a second in the UI
|
||||
docker('post', 'netfilter-mailcow', 'restart');
|
||||
$fail_count = 0;
|
||||
$regex_result = json_decode($redis->Get('F2B_REGEX'), true);
|
||||
while (empty($regex_result) && $fail_count < 10) {
|
||||
$regex_result = json_decode($redis->Get('F2B_REGEX'), true);
|
||||
$fail_count++;
|
||||
sleep(1);
|
||||
}
|
||||
if ($fail_count >= 10) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('reset_f2b_regex')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
elseif ($_data['action'] == "edit-regex") {
|
||||
if (!empty($_data['regex'])) {
|
||||
$rule_id = 1;
|
||||
$regex_array = array();
|
||||
foreach($_data['regex'] as $regex) {
|
||||
$regex_array[$rule_id] = $regex;
|
||||
$rule_id++;
|
||||
}
|
||||
$redis->Set('F2B_REGEX', json_encode($regex_array, JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => print_r($_data, true)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('object_modified', htmlspecialchars($network))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start actions in dependency of network
|
||||
if (!empty($_data['network'])) {
|
||||
$networks = (array)$_data['network'];
|
||||
foreach ($networks as $network) {
|
||||
// Unban network
|
||||
if ($_data['action'] == "unban") {
|
||||
if (valid_network($network)) {
|
||||
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||
try {
|
||||
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Whitelist network
|
||||
elseif ($_data['action'] == "whitelist") {
|
||||
if (valid_network($network)) {
|
||||
$redis->hSet('F2B_WHITELIST', $network, 1);
|
||||
$redis->hDel('F2B_BLACKLIST', $network, 1);
|
||||
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||
try {
|
||||
$redis->hSet('F2B_WHITELIST', $network, 1);
|
||||
$redis->hDel('F2B_BLACKLIST', $network, 1);
|
||||
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
|
@ -111,6 +193,7 @@ function fail2ban($_action, $_data = null) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
// Blacklist network
|
||||
elseif ($_data['action'] == "blacklist") {
|
||||
if (valid_network($network) && !in_array($network, array(
|
||||
'0.0.0.0',
|
||||
|
@ -119,9 +202,19 @@ function fail2ban($_action, $_data = null) {
|
|||
getenv('IPV4_NETWORK') . '0',
|
||||
getenv('IPV6_NETWORK')
|
||||
))) {
|
||||
$redis->hSet('F2B_BLACKLIST', $network, 1);
|
||||
$redis->hDel('F2B_WHITELIST', $network, 1);
|
||||
//$response = docker('post', 'netfilter-mailcow', 'restart');
|
||||
try {
|
||||
$redis->hSet('F2B_BLACKLIST', $network, 1);
|
||||
$redis->hDel('F2B_WHITELIST', $network, 1);
|
||||
//$response = docker('post', 'netfilter-mailcow', 'restart');
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
|
@ -132,23 +225,16 @@ function fail2ban($_action, $_data = null) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('redis_error', $e)
|
||||
'msg' => array('object_modified', htmlspecialchars($network))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('object_modified', htmlspecialchars($network))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Start default edit without specific action
|
||||
$is_now = fail2ban('get');
|
||||
if (!empty($is_now)) {
|
||||
$ban_time = intval((isset($_data['ban_time'])) ? $_data['ban_time'] : $is_now['ban_time']);
|
||||
|
|
|
@ -460,11 +460,17 @@ jQuery(function($){
|
|||
}
|
||||
})
|
||||
// App links
|
||||
function add_table_row(table_id) {
|
||||
function add_table_row(table_id, type) {
|
||||
var row = $('<tr />');
|
||||
if (type == "app_link") {
|
||||
cols = '<td><input class="input-sm form-control" data-id="app_links" type="text" name="app" required></td>';
|
||||
cols += '<td><input class="input-sm form-control" data-id="app_links" type="text" name="href" required></td>';
|
||||
cols += '<td><a href="#" role="button" class="btn btn-xs btn-default" type="button">Remove row</a></td>';
|
||||
cols += '<td><a href="#" role="button" class="btn btn-xs btn-default" type="button">">' + lang.remove_row + '</a></td>';
|
||||
} else if (type == "f2b_regex") {
|
||||
cols = '<td><input style="text-align:center" class="input-sm form-control" data-id="f2b_regex" type="text" value="+" disabled></td>';
|
||||
cols += '<td><input class="input-sm form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>';
|
||||
cols += '<td><a href="#" role="button" class="btn btn-xs btn-default" type="button">' + lang.remove_row + '</a></td>';
|
||||
}
|
||||
row.append(cols);
|
||||
table_id.append(row);
|
||||
}
|
||||
|
@ -472,8 +478,15 @@ jQuery(function($){
|
|||
e.preventDefault();
|
||||
$(this).parents('tr').remove();
|
||||
});
|
||||
$('#f2b_regex_table').on('click', 'tr a', function (e) {
|
||||
e.preventDefault();
|
||||
$(this).parents('tr').remove();
|
||||
});
|
||||
$('#add_app_link_row').click(function() {
|
||||
add_table_row($('#app_link_table'));
|
||||
add_table_row($('#app_link_table'), "app_link");
|
||||
});
|
||||
$('#add_f2b_regex_row').click(function() {
|
||||
add_table_row($('#f2b_regex_table'), "f2b_regex");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
"password": "Passwort",
|
||||
"password_repeat": "Passwort wiederholen",
|
||||
"port": "Port",
|
||||
"post_domain_add": "Der SOGo-Container, \"sogo-mailcow\" muss nach dem Hinzufügen einer Domain neugestartet werden!<br><br>Im Anschluss sollte die DNS-Konfiguration der Domain überprüft- und \"acme-mailcow\" gegebenenfalls neugestartet werden, um Änderungen am Zertifikat zu übernehmen (autoconfig.<domain>, autodiscover.<domain>).<br>Dieser Schritt ist optional und wird alle 24 Stunden automatisch ausgeführt.",
|
||||
"post_domain_add": "Der SOGo-Container - \"sogo-mailcow\" - muss nach dem Hinzufügen einer Domain neugestartet werden!<br><br>Im Anschluss sollte die DNS-Konfiguration der Domain überprüft- und \"acme-mailcow\" gegebenenfalls neugestartet werden, um Änderungen am Zertifikat zu übernehmen (autoconfig.<domain>, autodiscover.<domain>).<br>Dieser Schritt ist optional und wird alle 24 Stunden automatisch ausgeführt.",
|
||||
"private_comment": "Privater Kommentar",
|
||||
"public_comment": "Öffentlicher Kommentar",
|
||||
"quota_mb": "Speicherplatz (MiB)",
|
||||
|
@ -165,11 +165,13 @@
|
|||
"excludes": "Diese Empfänger ausschließen",
|
||||
"f2b_ban_time": "Bannzeit in Sekunden",
|
||||
"f2b_blacklist": "Blacklist für Netzwerke und Hosts",
|
||||
"f2b_filter": "Regex Filter",
|
||||
"f2b_list_info": "Ein Host oder Netzwerk auf der Blacklist wird immer eine Whitelist-Einheit überwiegen. <b>Die Aktualisierung der Liste dauert einige Sekunden.</b>",
|
||||
"f2b_max_attempts": "Max. Versuche",
|
||||
"f2b_netban_ipv4": "Netzbereich für IPv4-Bans (8-32)",
|
||||
"f2b_netban_ipv6": "Netzbereich für IPv6-Bans (8-128)",
|
||||
"f2b_parameters": "Fail2ban-Parameter",
|
||||
"f2b_regex_info": "Berücksichtigte Logs: SOGo, Postfix, Dovecot, PHP-FPM.",
|
||||
"f2b_retry_window": "Wiederholungen im Zeitraum von (s)",
|
||||
"f2b_whitelist": "Whitelist für Netzwerke und Hosts",
|
||||
"filter_table": "Tabelle filtern",
|
||||
|
@ -396,6 +398,7 @@
|
|||
"redis_error": "Redis Fehler: %s",
|
||||
"relayhost_invalid": "Mapeintrag %s ist ungültig",
|
||||
"release_send_failed": "Die Nachricht konnte nicht versendet werden: %s",
|
||||
"reset_f2b_regex": "Regex Filter konnten nicht in vorgegebener Zeit zurückgesetzt werden, bitte erneut versuchen oder die Webseite neu laden.",
|
||||
"resource_invalid": "Ressourcenname %s ist ungültig",
|
||||
"rl_timeframe": "Ratelimit-Zeitraum ist inkorrekt",
|
||||
"rspamd_ui_pw_length": "Rspamd UI-Passwort muss mindestens 6 Zeichen lang sein",
|
||||
|
|
|
@ -164,11 +164,13 @@
|
|||
"excludes": "Excludes these recipients",
|
||||
"f2b_ban_time": "Ban time (s)",
|
||||
"f2b_blacklist": "Blacklisted networks/hosts",
|
||||
"f2b_filter": "Regex filters",
|
||||
"f2b_list_info": "A blacklisted host or network will always outweigh a whitelist entity. <b>List updates will take a few seconds to be applied.</b>",
|
||||
"f2b_max_attempts": "Max. attempts",
|
||||
"f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)",
|
||||
"f2b_netban_ipv6": "IPv6 subnet size to apply ban on (8-128)",
|
||||
"f2b_parameters": "Fail2ban parameters",
|
||||
"f2b_regex_info": "Logs taken into consideration: SOGo, Postfix, Dovecot, PHP-FPM.",
|
||||
"f2b_retry_window": "Retry window (s) for max. attempts",
|
||||
"f2b_whitelist": "Whitelisted networks/hosts",
|
||||
"filter_table": "Filter table",
|
||||
|
@ -395,6 +397,7 @@
|
|||
"redis_error": "Redis error: %s",
|
||||
"relayhost_invalid": "Map entry %s is invalid",
|
||||
"release_send_failed": "Message could not be released: %s",
|
||||
"reset_f2b_regex": "Regex filter could not be reset in time, please try again or wait a few more seconds and reload the website.",
|
||||
"resource_invalid": "Resource name %s is invalid",
|
||||
"rl_timeframe": "Rate limit time frame is incorrect",
|
||||
"rspamd_ui_pw_length": "Rspamd UI password should be at least 6 chars long",
|
||||
|
|
|
@ -448,9 +448,9 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
|
|||
<label class="control-label col-sm-2" for="enc1"><?=$lang['add']['enc_method'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<select name="enc1" title="<?=$lang['add']['select'];?>" required>
|
||||
<option selected>TLS</option>
|
||||
<option>SSL</option>
|
||||
<option>PLAIN</option>
|
||||
<option value="SSL" selected>SSL</option>
|
||||
<option value="TLS">STARTTLS</option>
|
||||
<option value="PLAIN">PLAIN</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -44,9 +44,9 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
|
|||
<label class="control-label col-sm-2" for="enc1"><?=$lang['add']['enc_method'];?></label>
|
||||
<div class="col-sm-10">
|
||||
<select name="enc1" title="<?=$lang['add']['select'];?>" required>
|
||||
<option selected>TLS</option>
|
||||
<option>SSL</option>
|
||||
<option>PLAIN</option>
|
||||
<option value="SSL" selected>SSL</option>
|
||||
<option value="TLS">STARTTLS</option>
|
||||
<option value="PLAIN">PLAIN</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue