Merge pull request #4966 from mailcow/fix/bs5

BS5 UI fixes
This commit is contained in:
Niklas Meyer 2023-01-09 12:40:14 +01:00 committed by GitHub
commit 27c87de4ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 523 additions and 98 deletions

View File

@ -103,6 +103,7 @@ $template_data = [
'rsettings' => $rsettings, 'rsettings' => $rsettings,
'rspamd_regex_maps' => $rspamd_regex_maps, 'rspamd_regex_maps' => $rspamd_regex_maps,
'logo_specs' => customize('get', 'main_logo_specs'), 'logo_specs' => customize('get', 'main_logo_specs'),
'ip_check' => customize('get', 'ip_check'),
'password_complexity' => password_complexity('get'), 'password_complexity' => password_complexity('get'),
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'], 'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
'lang_admin' => json_encode($lang['admin']), 'lang_admin' => json_encode($lang['admin']),

View File

@ -370,3 +370,14 @@ button[aria-expanded='true'] > .caret {
.btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show { .btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {
background-color: #f0f0f0 !important; background-color: #f0f0f0 !important;
} }
div.dataTables_wrapper div.dataTables_filter {
text-align: left;
}
div.dataTables_wrapper div.dataTables_length {
text-align: right;
}
.dataTables_paginate, .dataTables_length, .dataTables_filter {
margin: 10px 0!important;
}

View File

@ -199,6 +199,10 @@
display: none !important; display: none !important;
} }
div.dataTables_wrapper div.dataTables_length {
text-align: left;
}
} }
@media (max-width: 350px) { @media (max-width: 350px) {

View File

@ -11,7 +11,86 @@
* Copyright 2011-2021 Twitter, Inc. * Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/ */
@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,300;0,400;0,700;1,400&display=swap");
/* source-sans-pro-300 - latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
src: url('/fonts/source-sans-pro-v21-latin-300.eot'); /* IE9 Compat Modes */
src: local(''),
url('/fonts/source-sans-pro-v21-latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('/fonts/source-sans-pro-v21-latin-300.woff2') format('woff2'), /* Super Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-300.woff') format('woff'), /* Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-300.ttf') format('truetype'), /* Safari, Android, iOS */
url('/fonts/source-sans-pro-v21-latin-300.svg#SourceSansPro') format('svg'); /* Legacy iOS */
}
/* source-sans-pro-300italic - latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 300;
src: url('/fonts/source-sans-pro-v21-latin-300italic.eot'); /* IE9 Compat Modes */
src: local(''),
url('/fonts/source-sans-pro-v21-latin-300italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('/fonts/source-sans-pro-v21-latin-300italic.woff2') format('woff2'), /* Super Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-300italic.woff') format('woff'), /* Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-300italic.ttf') format('truetype'), /* Safari, Android, iOS */
url('/fonts/source-sans-pro-v21-latin-300italic.svg#SourceSansPro') format('svg'); /* Legacy iOS */
}
/* source-sans-pro-regular - latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: url('/fonts/source-sans-pro-v21-latin-regular.eot'); /* IE9 Compat Modes */
src: local(''),
url('/fonts/source-sans-pro-v21-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('/fonts/source-sans-pro-v21-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-regular.woff') format('woff'), /* Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('/fonts/source-sans-pro-v21-latin-regular.svg#SourceSansPro') format('svg'); /* Legacy iOS */
}
/* source-sans-pro-italic - latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 400;
src: url('/fonts/source-sans-pro-v21-latin-italic.eot'); /* IE9 Compat Modes */
src: local(''),
url('/fonts/source-sans-pro-v21-latin-italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('/fonts/source-sans-pro-v21-latin-italic.woff2') format('woff2'), /* Super Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-italic.woff') format('woff'), /* Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-italic.ttf') format('truetype'), /* Safari, Android, iOS */
url('/fonts/source-sans-pro-v21-latin-italic.svg#SourceSansPro') format('svg'); /* Legacy iOS */
}
/* source-sans-pro-700 - latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: url('/fonts/source-sans-pro-v21-latin-700.eot'); /* IE9 Compat Modes */
src: local(''),
url('/fonts/source-sans-pro-v21-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('/fonts/source-sans-pro-v21-latin-700.woff2') format('woff2'), /* Super Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-700.woff') format('woff'), /* Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */
url('/fonts/source-sans-pro-v21-latin-700.svg#SourceSansPro') format('svg'); /* Legacy iOS */
}
/* source-sans-pro-700italic - latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: italic;
font-weight: 700;
src: url('/fonts/source-sans-pro-v21-latin-700italic.eot'); /* IE9 Compat Modes */
src: local(''),
url('/fonts/source-sans-pro-v21-latin-700italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('/fonts/source-sans-pro-v21-latin-700italic.woff2') format('woff2'), /* Super Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-700italic.woff') format('woff'), /* Modern Browsers */
url('/fonts/source-sans-pro-v21-latin-700italic.ttf') format('truetype'), /* Safari, Android, iOS */
url('/fonts/source-sans-pro-v21-latin-700italic.svg#SourceSansPro') format('svg'); /* Legacy iOS */
}
:root { :root {
--bs-blue: #158cba; --bs-blue: #158cba;
--bs-indigo: #6610f2; --bs-indigo: #6610f2;

View File

@ -358,3 +358,11 @@ table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
background: #333; background: #333;
} }
span.mail-address-item {
background-color: #333;
border-radius: 4px;
border: 1px solid #555;
padding: 2px 7px;
display: inline-block;
margin: 2px 6px 2px 0;
}

View File

@ -65,6 +65,7 @@ $template_data = [
'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60), 'solr_uptime' => round($solr_status['status']['dovecot-fts']['uptime'] / 1000 / 60 / 60),
'clamd_status' => $clamd_status, 'clamd_status' => $clamd_status,
'containers' => $containers, 'containers' => $containers,
'ip_check' => customize('get', 'ip_check'),
'lang_admin' => json_encode($lang['admin']), 'lang_admin' => json_encode($lang['admin']),
'lang_debug' => json_encode($lang['debug']), 'lang_debug' => json_encode($lang['debug']),
'lang_datatables' => json_encode($lang['datatables']), 'lang_datatables' => json_encode($lang['datatables']),

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -160,6 +160,25 @@ function customize($_action, $_item, $_data = null) {
'msg' => 'ui_texts' 'msg' => 'ui_texts'
); );
break; break;
case 'ip_check':
$ip_check = ($_data['ip_check_opt_in'] == "1") ? 1 : 0;
try {
$redis->set('IP_CHECK', $ip_check);
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e)
);
return false;
}
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => 'ip_check_opt_in_modified'
);
break;
} }
break; break;
case 'delete': case 'delete':
@ -276,6 +295,20 @@ function customize($_action, $_item, $_data = null) {
return false; return false;
} }
break; break;
case 'ip_check':
try {
$ip_check = ($ip_check = $redis->get('IP_CHECK')) ? $ip_check : 0;
return $ip_check;
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_item, $_data),
'msg' => array('redis_error', $e)
);
return false;
}
break;
} }
break; break;
} }

View File

@ -2879,67 +2879,68 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'access_denied' 'msg' => 'extended_sender_acl_denied'
); );
return false;
} }
$extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl'])); else {
foreach ($extra_acls as $i => &$extra_acl) { $extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl']));
if (empty($extra_acl)) { foreach ($extra_acls as $i => &$extra_acl) {
continue; if (empty($extra_acl)) {
} continue;
if (substr($extra_acl, 0, 1) === "@") { }
$extra_acl = ltrim($extra_acl, '@'); if (substr($extra_acl, 0, 1) === "@") {
} $extra_acl = ltrim($extra_acl, '@');
if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) { }
$_SESSION['return'][] = array( if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) {
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl))
);
unset($extra_acls[$i]);
continue;
}
$domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) {
$extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
if (in_array($extra_acl_domain, $domains)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('extra_acl_invalid_domain', $extra_acl_domain) 'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl))
); );
unset($extra_acls[$i]); unset($extra_acls[$i]);
continue; continue;
} }
} $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
else { if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) {
if (in_array($extra_acl, $domains)) { $extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
$_SESSION['return'][] = array( if (in_array($extra_acl_domain, $domains)) {
'type' => 'danger', $_SESSION['return'][] = array(
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'type' => 'danger',
'msg' => array('extra_acl_invalid_domain', $extra_acl_domain) 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
); 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
unset($extra_acls[$i]); );
continue; unset($extra_acls[$i]);
continue;
}
}
else {
if (in_array($extra_acl, $domains)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
);
unset($extra_acls[$i]);
continue;
}
$extra_acl = '@' . $extra_acl;
} }
$extra_acl = '@' . $extra_acl;
} }
} $extra_acls = array_filter($extra_acls);
$extra_acls = array_filter($extra_acls); $extra_acls = array_values($extra_acls);
$extra_acls = array_values($extra_acls); $extra_acls = array_unique($extra_acls);
$extra_acls = array_unique($extra_acls); $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username");
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username");
$stmt->execute(array(
':username' => $username
));
foreach ($extra_acls as $sender_acl_external) {
$stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`)
VALUES (:sender_acl, :username, 1)");
$stmt->execute(array( $stmt->execute(array(
':sender_acl' => $sender_acl_external,
':username' => $username ':username' => $username
)); ));
foreach ($extra_acls as $sender_acl_external) {
$stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`)
VALUES (:sender_acl, :username, 1)");
$stmt->execute(array(
':sender_acl' => $sender_acl_external,
':username' => $username
));
}
} }
} }
if (isset($_data['sender_acl'])) { if (isset($_data['sender_acl'])) {

View File

@ -12,14 +12,22 @@ $(document).ready(function() {
$.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}}); $.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}});
} }
$(".generate_password").click(function( event ) { $(".generate_password").click(async function( event ) {
try {
var password_policy = await window.fetch("/api/v1/get/passwordpolicy", { method:'GET', cache:'no-cache' });
var password_policy = await password_policy.json();
random_passwd_length = password_policy.length;
} catch(err) {
var random_passwd_length = 8;
}
event.preventDefault(); event.preventDefault();
$('[data-hibp]').trigger('input'); $('[data-hibp]').trigger('input');
if (typeof($(this).closest("form").data('pwgen-length')) == "number") { if (typeof($(this).closest("form").data('pwgen-length')) == "number") {
var random_passwd = GPW.pronounceable($(this).closest("form").data('pwgen-length')) var random_passwd = GPW.pronounceable($(this).closest("form").data('pwgen-length'))
} }
else { else {
var random_passwd = GPW.pronounceable(8) var random_passwd = GPW.pronounceable(random_passwd_length)
} }
$(this).closest("form").find('[data-pwgen-field]').attr('type', 'text'); $(this).closest("form").find('[data-pwgen-field]').attr('type', 'text');
$(this).closest("form").find('[data-pwgen-field]').val(random_passwd); $(this).closest("form").find('[data-pwgen-field]').val(random_passwd);

View File

@ -70,8 +70,13 @@ jQuery(function($){
} }
$('#domainadminstable').DataTable({ $('#domainadminstable').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -143,8 +148,13 @@ jQuery(function($){
} }
$('#oauth2clientstable').DataTable({ $('#oauth2clientstable').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -206,8 +216,13 @@ jQuery(function($){
} }
$('#adminstable').DataTable({ $('#adminstable').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -272,8 +287,13 @@ jQuery(function($){
} }
$('#forwardinghoststable').DataTable({ $('#forwardinghoststable').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -330,8 +350,13 @@ jQuery(function($){
} }
$('#relayhoststable').DataTable({ $('#relayhoststable').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -402,8 +427,13 @@ jQuery(function($){
} }
$('#transportstable').DataTable({ $('#transportstable').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",

View File

@ -51,7 +51,40 @@ $(document).ready(function() {
showVersionModal("Version " + mailcow_info.version_tag, mailcow_info.version_tag); showVersionModal("Version " + mailcow_info.version_tag, mailcow_info.version_tag);
}) })
// get public ips // get public ips
get_public_ips(); $("#host_show_ip").click(function(){
$("#host_show_ip").find(".text").addClass("d-none");
$("#host_show_ip").find(".spinner-border").removeClass("d-none");
window.fetch("/api/v1/get/status/host/ip", { method:'GET', cache:'no-cache' }).then(function(response) {
return response.json();
}).then(function(data) {
console.log(data);
// display host ips
if (data.ipv4)
$("#host_ipv4").text(data.ipv4);
if (data.ipv6)
$("#host_ipv6").text(data.ipv6);
$("#host_show_ip").addClass("d-none");
$("#host_show_ip").find(".text").removeClass("d-none");
$("#host_show_ip").find(".spinner-border").addClass("d-none");
$("#host_ipv4").removeClass("d-none");
$("#host_ipv6").removeClass("d-none");
$("#host_ipv6").removeClass("text-danger");
$("#host_ipv4").addClass("d-block");
$("#host_ipv6").addClass("d-block");
}).catch(function(error){
console.log(error);
$("#host_ipv6").removeClass("d-none");
$("#host_ipv6").addClass("d-block");
$("#host_ipv6").addClass("text-danger");
$("#host_ipv6").text(lang_debug.error_show_ip);
$("#host_show_ip").find(".text").removeClass("d-none");
$("#host_show_ip").find(".spinner-border").addClass("d-none");
});
});
update_container_stats(); update_container_stats();
}); });
jQuery(function($){ jQuery(function($){
@ -86,8 +119,13 @@ jQuery(function($){
} }
$('#autodiscover_log').DataTable({ $('#autodiscover_log').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -143,8 +181,13 @@ jQuery(function($){
} }
$('#postfix_log').DataTable({ $('#postfix_log').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -185,8 +228,13 @@ jQuery(function($){
} }
$('#watchdog_log').DataTable({ $('#watchdog_log').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -231,8 +279,13 @@ jQuery(function($){
} }
$('#api_log').DataTable({ $('#api_log').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -284,8 +337,13 @@ jQuery(function($){
} }
$('#rl_log').DataTable({ $('#rl_log').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -375,8 +433,13 @@ jQuery(function($){
} }
$('#ui_logs').DataTable({ $('#ui_logs').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -446,8 +509,13 @@ jQuery(function($){
} }
$('#sasl_logs').DataTable({ $('#sasl_logs').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -494,8 +562,13 @@ jQuery(function($){
} }
$('#acme_log').DataTable({ $('#acme_log').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -531,8 +604,13 @@ jQuery(function($){
} }
$('#netfilter_log').DataTable({ $('#netfilter_log').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -573,8 +651,13 @@ jQuery(function($){
} }
$('#sogo_log').DataTable({ $('#sogo_log').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -615,8 +698,13 @@ jQuery(function($){
} }
$('#dovecot_log').DataTable({ $('#dovecot_log').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -718,8 +806,13 @@ jQuery(function($){
} }
$('#rspamd_history').DataTable({ $('#rspamd_history').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order: [[0, 'desc']], order: [[0, 'desc']],
ajax: { ajax: {
@ -1224,20 +1317,6 @@ function update_container_stats(timeout=5){
// run again in n seconds // run again in n seconds
setTimeout(update_container_stats, timeout * 1000); setTimeout(update_container_stats, timeout * 1000);
} }
// get public ips
function get_public_ips(){
window.fetch("/api/v1/get/status/host/ip", {method:'GET',cache:'no-cache'}).then(function(response) {
return response.json();
}).then(function(data) {
console.log(data);
// display host ips
if (data.ipv4)
$("#host_ipv4").text(data.ipv4);
if (data.ipv6)
$("#host_ipv6").text(data.ipv6);
});
}
// format hosts uptime seconds to readable string // format hosts uptime seconds to readable string
function formatUptime(seconds){ function formatUptime(seconds){
seconds = Number(seconds); seconds = Number(seconds);

View File

@ -78,8 +78,13 @@ jQuery(function($){
} }
function draw_wl_policy_domain_table() { function draw_wl_policy_domain_table() {
$('#wl_policy_domain_table').DataTable({ $('#wl_policy_domain_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -133,8 +138,13 @@ jQuery(function($){
} }
function draw_bl_policy_domain_table() { function draw_bl_policy_domain_table() {
$('#bl_policy_domain_table').DataTable({ $('#bl_policy_domain_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",

View File

@ -433,8 +433,13 @@ jQuery(function($){
} }
var table = $('#domain_table').DataTable({ var table = $('#domain_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -619,9 +624,13 @@ jQuery(function($){
} }
$('#templates_domain_table').DataTable({ $('#templates_domain_table').DataTable({
responsive : true, responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order:[[2, 'desc']], order:[[2, 'desc']],
ajax: { ajax: {
@ -817,16 +826,26 @@ jQuery(function($){
} }
$('#mailbox_table').DataTable({ $('#mailbox_table').DataTable({
responsive : true, responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
url: "/api/v1/get/mailbox/reduced", url: "/api/v1/get/mailbox/reduced",
dataSrc: function(json){ dataSrc: function(json){
$.each(json, function (i, item) { $.each(json, function (i, item) {
item.quota = item.quota_used + "/" + item.quota; item.quota = {
sortBy: item.quota_used,
value: item.quota
}
item.quota.value = (item.quota.value == 0 ? "∞" : humanFileSize(item.quota.value));
item.quota.value = humanFileSize(item.quota_used) + "/" + item.quota.value;
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox); item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
item.last_mail_login = item.last_imap_login + '/' + item.last_pop3_login + '/' + item.last_smtp_login; item.last_mail_login = item.last_imap_login + '/' + item.last_pop3_login + '/' + item.last_smtp_login;
/* /*
@ -931,14 +950,10 @@ jQuery(function($){
}, },
{ {
title: lang.domain_quota, title: lang.domain_quota,
data: 'quota', data: 'quota.value',
responsivePriority: 8, responsivePriority: 8,
defaultContent: '', defaultContent: '',
render: function (data, type) { orderData: 23
data = data.split("/");
var of_q = (data[1] == 0 ? "∞" : humanFileSize(data[1]));
return humanFileSize(data[0]) + " / " + of_q;
}
}, },
{ {
title: lang.last_mail_login, title: lang.last_mail_login,
@ -1064,6 +1079,13 @@ jQuery(function($){
responsivePriority: 6, responsivePriority: 6,
defaultContent: '' defaultContent: ''
}, },
{
title: "",
data: 'quota.sortBy',
responsivePriority: 8,
defaultContent: '',
className: "d-none"
},
] ]
}); });
} }
@ -1075,9 +1097,13 @@ jQuery(function($){
} }
$('#templates_mbox_table').DataTable({ $('#templates_mbox_table').DataTable({
responsive : true, responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order:[[2, 'desc']], order:[[2, 'desc']],
ajax: { ajax: {
@ -1287,8 +1313,13 @@ jQuery(function($){
} }
$('#resource_table').DataTable({ $('#resource_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -1413,8 +1444,13 @@ jQuery(function($){
} }
$('#bcc_table').DataTable({ $('#bcc_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order:[[2, 'desc']], order:[[2, 'desc']],
ajax: { ajax: {
@ -1510,8 +1546,13 @@ jQuery(function($){
} }
$('#recipient_map_table').DataTable({ $('#recipient_map_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order:[[2, 'desc']], order:[[2, 'desc']],
ajax: { ajax: {
@ -1594,8 +1635,13 @@ jQuery(function($){
} }
$('#tls_policy_table').DataTable({ $('#tls_policy_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order:[[2, 'desc']], order:[[2, 'desc']],
ajax: { ajax: {
@ -1688,8 +1734,13 @@ jQuery(function($){
} }
$('#alias_table').DataTable({ $('#alias_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order:[[2, 'desc']], order:[[2, 'desc']],
ajax: { ajax: {
@ -1829,8 +1880,13 @@ jQuery(function($){
} }
$('#aliasdomain_table').DataTable({ $('#aliasdomain_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -1911,8 +1967,13 @@ jQuery(function($){
} }
$('#sync_job_table').DataTable({ $('#sync_job_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order:[[2, 'desc']], order:[[2, 'desc']],
ajax: { ajax: {
@ -2051,9 +2112,14 @@ jQuery(function($){
} }
var table = $('#filter_table').DataTable({ var table = $('#filter_table').DataTable({
responsive: true,
autoWidth: false, autoWidth: false,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
order:[[2, 'desc']], order:[[2, 'desc']],
ajax: { ajax: {

View File

@ -14,8 +14,13 @@ jQuery(function($){
}); });
function draw_quarantine_table() { function draw_quarantine_table() {
$('#quarantinetable').DataTable({ $('#quarantinetable').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -129,9 +134,15 @@ jQuery(function($){
title: lang.received, title: lang.received,
data: 'created', data: 'created',
defaultContent: '', defaultContent: '',
render: function (data,type) { createdCell: function(td, cellData) {
var date = new Date(data ? data * 1000 : 0); $(td).attr({
return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); "data-order": cellData,
"data-sort": cellData
});
var date = new Date(cellData ? cellData * 1000 : 0);
var dateString = date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
$(td).html(dateString);
} }
}, },
{ {

View File

@ -35,8 +35,13 @@ jQuery(function($){
} }
$('#queuetable').DataTable({ $('#queuetable').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",

View File

@ -135,8 +135,13 @@ jQuery(function($){
} }
$('#tla_table').DataTable({ $('#tla_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -216,8 +221,13 @@ jQuery(function($){
} }
$('#sync_job_table').DataTable({ $('#sync_job_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -366,8 +376,13 @@ jQuery(function($){
} }
$('#app_passwd_table').DataTable({ $('#app_passwd_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -456,8 +471,13 @@ jQuery(function($){
} }
$('#wl_policy_mailbox_table').DataTable({ $('#wl_policy_mailbox_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",
@ -521,8 +541,13 @@ jQuery(function($){
} }
$('#bl_policy_mailbox_table').DataTable({ $('#bl_policy_mailbox_table').DataTable({
responsive: true,
processing: true, processing: true,
serverSide: false, serverSide: false,
stateSave: true,
dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" +
"tr" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
language: lang_datatables, language: lang_datatables,
ajax: { ajax: {
type: "GET", type: "GET",

View File

@ -561,6 +561,15 @@ if (isset($_GET['query'])) {
echo '{}'; echo '{}';
} }
break; break;
default:
$password_complexity_rules = password_complexity('get');
if ($password_complexity_rules !== false) {
process_get_return($password_complexity_rules);
}
else {
echo '{}';
}
break;
} }
break; break;
@ -1544,14 +1553,15 @@ if (isset($_GET['query'])) {
} }
else if ($extra == "ip") { else if ($extra == "ip") {
// get public ips // get public ips
$curl = curl_init(); $curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://ipv4.mailcow.email');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_POST, 0);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($curl, CURLOPT_TIMEOUT, 15);
curl_setopt($curl, CURLOPT_URL, 'http://ipv4.mailcow.email');
$ipv4 = curl_exec($curl); $ipv4 = curl_exec($curl);
curl_setopt($curl, CURLOPT_URL, 'http://ipv6.mailcow.email'); curl_setopt($curl, CURLOPT_URL, 'http://ipv6.mailcow.email');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 0);
$ipv6 = curl_exec($curl); $ipv6 = curl_exec($curl);
$ips = array( $ips = array(
"ipv4" => $ipv4, "ipv4" => $ipv4,
@ -1913,6 +1923,9 @@ if (isset($_GET['query'])) {
case "ui_texts": case "ui_texts":
process_edit_return(customize('edit', 'ui_texts', $attr)); process_edit_return(customize('edit', 'ui_texts', $attr));
break; break;
case "ip_check":
process_edit_return(customize('edit', 'ip_check', $attr));
break;
case "self": case "self":
if ($_SESSION['mailcow_cc_role'] == "domainadmin") { if ($_SESSION['mailcow_cc_role'] == "domainadmin") {
process_edit_return(domain_admin('edit', $attr)); process_edit_return(domain_admin('edit', $attr));

View File

@ -204,6 +204,9 @@
"include_exclude": "Ein- und Ausschlüsse", "include_exclude": "Ein- und Ausschlüsse",
"include_exclude_info": "Ohne Auswahl werden <b>alle Mailboxen</b> adressiert.", "include_exclude_info": "Ohne Auswahl werden <b>alle Mailboxen</b> adressiert.",
"includes": "Diese Empfänger einschließen", "includes": "Diese Empfänger einschließen",
"ip_check": "IP Check",
"ip_check_disabled": "IP check ist deaktiviert. Unter dem angegebenen Pfad kann es aktiviert werden<br> <strong>System > Konfiguration > Einstellungen > UI-Anpassung</strong>",
"ip_check_opt_in": "Opt-In für die Nutzung der Drittanbieter-Dienste <strong>ipv4.mailcow.email</strong> und <strong>ipv6.mailcow.email</strong> zur Auflösung externer IP-Adressen.",
"is_mx_based": "MX-basiert", "is_mx_based": "MX-basiert",
"last_applied": "Zuletzt angewendet", "last_applied": "Zuletzt angewendet",
"license_info": "Eine Lizenz ist nicht erforderlich, hilft jedoch der Entwicklung mailcows.<br><a href=\"https://www.servercow.de/mailcow#sal\" target=\"_blank\" alt=\"SAL Bestellung\">Hier kann die mailcow-GUID registriert werden.</a> Alternativ ist <a href=\"https://www.servercow.de/mailcow#support\" target=\"_blank\" alt=\"SAL Bestellung\">die Bestellung von Support-Paketen möglich</a>.", "license_info": "Eine Lizenz ist nicht erforderlich, hilft jedoch der Entwicklung mailcows.<br><a href=\"https://www.servercow.de/mailcow#sal\" target=\"_blank\" alt=\"SAL Bestellung\">Hier kann die mailcow-GUID registriert werden.</a> Alternativ ist <a href=\"https://www.servercow.de/mailcow#support\" target=\"_blank\" alt=\"SAL Bestellung\">die Bestellung von Support-Paketen möglich</a>.",
@ -363,6 +366,7 @@
"domain_not_empty": "Domain %s ist nicht leer", "domain_not_empty": "Domain %s ist nicht leer",
"domain_not_found": "Domain %s nicht gefunden", "domain_not_found": "Domain %s nicht gefunden",
"domain_quota_m_in_use": "Domain-Speicherplatzlimit muss größer oder gleich %d MiB sein", "domain_quota_m_in_use": "Domain-Speicherplatzlimit muss größer oder gleich %d MiB sein",
"extended_sender_acl_denied": "Keine Rechte zum setzen von externen Absenderadressen",
"extra_acl_invalid": "Externe Absenderadresse \"%s\" ist ungültig", "extra_acl_invalid": "Externe Absenderadresse \"%s\" ist ungültig",
"extra_acl_invalid_domain": "Externe Absenderadresse \"%s\" verwendet eine ungültige Domain", "extra_acl_invalid_domain": "Externe Absenderadresse \"%s\" verwendet eine ungültige Domain",
"fido2_verification_failed": "FIDO2-Verifizierung fehlgeschlagen: %s", "fido2_verification_failed": "FIDO2-Verifizierung fehlgeschlagen: %s",
@ -494,6 +498,7 @@
"current_time": "Systemzeit", "current_time": "Systemzeit",
"disk_usage": "Festplattennutzung", "disk_usage": "Festplattennutzung",
"docs": "Dokumente", "docs": "Dokumente",
"error_show_ip": "konnte die öffentlichen IP Adressen nicht auflösen",
"external_logs": "Externe Logs", "external_logs": "Externe Logs",
"history_all_servers": "History (alle Server)", "history_all_servers": "History (alle Server)",
"in_memory_logs": "In-memory Logs", "in_memory_logs": "In-memory Logs",
@ -506,6 +511,7 @@
"online_users": "Benutzer online", "online_users": "Benutzer online",
"restart_container": "Neustart", "restart_container": "Neustart",
"service": "Dienst", "service": "Dienst",
"show_ip": "Zeige öffentliche IP",
"size": "Größe", "size": "Größe",
"solr_dead": "Solr startet, ist deaktiviert oder temporär nicht erreichbar.", "solr_dead": "Solr startet, ist deaktiviert oder temporär nicht erreichbar.",
"solr_status": "Solr Status", "solr_status": "Solr Status",
@ -1001,6 +1007,7 @@
"forwarding_host_removed": "Weiterleitungs-Host %s wurde entfernt", "forwarding_host_removed": "Weiterleitungs-Host %s wurde entfernt",
"global_filter_written": "Filterdatei wurde erfolgreich geschrieben", "global_filter_written": "Filterdatei wurde erfolgreich geschrieben",
"hash_deleted": "Hash wurde gelöscht", "hash_deleted": "Hash wurde gelöscht",
"ip_check_opt_in_modified": "IP Check wurde erfolgreich gespeichert",
"item_deleted": "Objekt %s wurde entfernt", "item_deleted": "Objekt %s wurde entfernt",
"item_released": "Objekt %s freigegeben", "item_released": "Objekt %s freigegeben",
"items_deleted": "Objekt(e) %s wurde(n) erfolgreich entfernt", "items_deleted": "Objekt(e) %s wurde(n) erfolgreich entfernt",

View File

@ -206,6 +206,9 @@
"include_exclude": "Include/Exclude", "include_exclude": "Include/Exclude",
"include_exclude_info": "By default - with no selection - <b>all mailboxes</b> are addressed", "include_exclude_info": "By default - with no selection - <b>all mailboxes</b> are addressed",
"includes": "Include these recipients", "includes": "Include these recipients",
"ip_check": "IP Check",
"ip_check_disabled": "IP check is disabled. You can enable it under<br> <strong>System > Configuration > Options > Customize</strong>",
"ip_check_opt_in": "Opt-In for using third party service <strong>ipv4.mailcow.email</strong> and <strong>ipv6.mailcow.email</strong> to resolve external IP addresses.",
"is_mx_based": "MX based", "is_mx_based": "MX based",
"last_applied": "Last applied", "last_applied": "Last applied",
"license_info": "A license is not required but helps further development.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Register your GUID here</a> or <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Support order\">buy support for your mailcow installation.</a>", "license_info": "A license is not required but helps further development.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Register your GUID here</a> or <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Support order\">buy support for your mailcow installation.</a>",
@ -363,6 +366,7 @@
"domain_not_empty": "Cannot remove non-empty domain %s", "domain_not_empty": "Cannot remove non-empty domain %s",
"domain_not_found": "Domain %s not found", "domain_not_found": "Domain %s not found",
"domain_quota_m_in_use": "Domain quota must be greater or equal to %s MiB", "domain_quota_m_in_use": "Domain quota must be greater or equal to %s MiB",
"extended_sender_acl_denied": "missing ACL to set external sender addresses",
"extra_acl_invalid": "External sender address \"%s\" is invalid", "extra_acl_invalid": "External sender address \"%s\" is invalid",
"extra_acl_invalid_domain": "External sender \"%s\" uses an invalid domain", "extra_acl_invalid_domain": "External sender \"%s\" uses an invalid domain",
"fido2_verification_failed": "FIDO2 verification failed: %s", "fido2_verification_failed": "FIDO2 verification failed: %s",
@ -497,6 +501,7 @@
"current_time": "System Time", "current_time": "System Time",
"disk_usage": "Disk usage", "disk_usage": "Disk usage",
"docs": "Docs", "docs": "Docs",
"error_show_ip": "Could not resolve the public IP addresses",
"external_logs": "External logs", "external_logs": "External logs",
"history_all_servers": "History (all servers)", "history_all_servers": "History (all servers)",
"in_memory_logs": "In-memory logs", "in_memory_logs": "In-memory logs",
@ -509,6 +514,7 @@
"online_users": "Users online", "online_users": "Users online",
"restart_container": "Restart", "restart_container": "Restart",
"service": "Service", "service": "Service",
"show_ip": "Show public IP",
"size": "Size", "size": "Size",
"solr_dead": "Solr is starting, disabled or died.", "solr_dead": "Solr is starting, disabled or died.",
"solr_status": "Solr status", "solr_status": "Solr status",
@ -1013,6 +1019,7 @@
"forwarding_host_removed": "Forwarding host %s has been removed", "forwarding_host_removed": "Forwarding host %s has been removed",
"global_filter_written": "Filter was successfully written to file", "global_filter_written": "Filter was successfully written to file",
"hash_deleted": "Hash deleted", "hash_deleted": "Hash deleted",
"ip_check_opt_in_modified": "IP check was saved successfully",
"item_deleted": "Item %s successfully deleted", "item_deleted": "Item %s successfully deleted",
"item_released": "Item %s released", "item_released": "Item %s released",
"items_deleted": "Item %s successfully deleted", "items_deleted": "Item %s successfully deleted",

View File

@ -33,6 +33,20 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
<legend style="padding-top:20px" unselectable="on">{{ lang.admin.ip_check }}</legend><hr />
<div id="ip_check">
<form class="form" data-id="ip_check" role="form" method="post">
<div class="mb-4">
<input class="form-check-input" type="checkbox" value="1" name="ip_check_opt_in" id="ip_check_opt_in" {% if ip_check == 1 %}checked{% endif %}>
<label class="form-check-label" for="ip_check_opt_in">
{{ lang.admin.ip_check_opt_in|raw }}
</label>
</div>
<p><div class="btn-group">
<button class="btn btn-sm btn-xs-half d-block d-sm-inline btn-success" data-action="edit_selected" data-item="admin" data-id="ip_check" data-reload="no" data-api-url='edit/ip_check' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
</div></p>
</form>
</div>
<legend>{{ lang.admin.app_links }}</legend><hr /> <legend>{{ lang.admin.app_links }}</legend><hr />
<p class="text-muted">{{ lang.admin.merged_vars_hint|raw }}</p> <p class="text-muted">{{ lang.admin.merged_vars_hint|raw }}</p>
<form class="form-inline" data-id="app_links" role="form" method="post"> <form class="form-inline" data-id="app_links" role="form" method="post">

View File

@ -36,7 +36,7 @@
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="rlyhost_password">{{ lang.admin.password }}</label> <label for="rlyhost_password">{{ lang.admin.password }}</label>
<input class="form-control" id="rlyhost_password" name="password"> <input class="form-control" id="rlyhost_password" name="password" type="password">
</div> </div>
<button class="btn btn-sm d-block d-sm-inline btn-success" data-action="add_item" data-id="rlyhost" data-api-url='add/relayhost' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button> <button class="btn btn-sm d-block d-sm-inline btn-success" data-action="add_item" data-id="rlyhost" data-api-url='add/relayhost' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button>
</form> </form>
@ -86,7 +86,7 @@
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="transport_password">{{ lang.admin.password }}</label> <label for="transport_password">{{ lang.admin.password }}</label>
<input class="form-control" id="transport_password" name="password"> <input class="form-control" id="transport_password" name="password" type="password">
</div> </div>
<div class="mb-2"> <div class="mb-2">
<label> <label>

View File

@ -52,8 +52,18 @@
<tr> <tr>
<td>IPs</td> <td>IPs</td>
<td class="text-break"> <td class="text-break">
<span class="d-block" id="host_ipv4">-</span> {% if ip_check == 1 %}
<span class="d-block" id="host_ipv6">-</span> <span class="d-none" id="host_ipv4">-</span>
<span class="d-none mb-2" id="host_ipv6">-</span>
<button class="d-block btn btn-primary btn-sm" id="host_show_ip">
<span class="text">{{ lang.debug.show_ip }}</span>
<div class="spinner-border spinner-border-sm d-none" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</button>
{% else %}
<span class="d-block">{{ lang.admin.ip_check_disabled|raw }}</span>
{% endif %}
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@ -200,8 +200,10 @@
{% if sender_acl_handles.external_sender_aliases %} {% if sender_acl_handles.external_sender_aliases %}
{% set ext_sender_acl = sender_acl_handles.external_sender_aliases|join(', ') %} {% set ext_sender_acl = sender_acl_handles.external_sender_aliases|join(', ') %}
{% endif %} {% endif %}
<input type="text" class="form-control" name="extended_sender_acl" value="{{ ext_sender_acl }}" placeholder="user1@example.com, user2@example.org, @example.com, ..."> {% if acl.extend_sender_acl and acl.extend_sender_acl == 1 %}
<small class="text-muted">{{ lang.edit.extended_sender_acl_info|raw }}</small> <input type="text" class="form-control" name="extended_sender_acl" value="{{ ext_sender_acl }}" placeholder="user1@example.com, user2@example.org, @example.com, ...">
<small class="text-muted">{{ lang.edit.extended_sender_acl_info|raw }}</small>
{% endif %}
</div> </div>
</div> </div>
<div class="row"> <div class="row">

View File

@ -4,18 +4,18 @@
<div id="mail-content" class="responsive-tabs"> <div id="mail-content" class="responsive-tabs">
<ul class="nav nav-tabs" role="tablist"> <ul class="nav nav-tabs" role="tablist">
<li class="nav-item dropdown" role="presentation"> <li class="nav-item dropdown" role="presentation">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.domains }}</a> <a class="nav-link dropdown-toggle active" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.domains }}</a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><button class="dropdown-item" aria-selected="false" aria-controls="tab-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domains">{{ lang.mailbox.domains }}</button></li> <li><button class="dropdown-item" aria-selected="false" aria-controls="tab-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domains">{{ lang.mailbox.domains }}</button></li>
<li><button class="dropdown-item {% if mailcow_cc_role != 'admin' %} d-none{% endif %}" aria-selected="false" aria-controls="tab-templates-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-domains">{{ lang.mailbox.templates }}</button></li> <li><button class="dropdown-item {% if mailcow_cc_role != 'admin' %} d-none{% endif %}" aria-selected="false" aria-controls="tab-templates-domains" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-domains">{{ lang.mailbox.templates }}</button></li>
</ul> </ul>
</li> </li>
<li class="nav-item dropdown" role="presentation"> <li class="nav-item dropdown" role="presentation">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.mailboxes }}</a> <a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.mailboxes }}</a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><button class="dropdown-item" aria-selected="false" aria-controls="tab-mailboxes" role="tab" data-bs-toggle="tab" data-bs-target="#tab-mailboxes">{{ lang.mailbox.mailboxes }}</button></li> <li><button class="dropdown-item" aria-selected="false" aria-controls="tab-mailboxes" role="tab" data-bs-toggle="tab" data-bs-target="#tab-mailboxes">{{ lang.mailbox.mailboxes }}</button></li>
<li><button class="dropdown-item {% if mailcow_cc_role != 'admin' %} d-none{% endif %}" aria-selected="false" aria-controls="tab-templates-mbox" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-mbox">{{ lang.mailbox.templates }}</button></li> <li><button class="dropdown-item {% if mailcow_cc_role != 'admin' %} d-none{% endif %}" aria-selected="false" aria-controls="tab-templates-mbox" role="tab" data-bs-toggle="tab" data-bs-target="#tab-templates-mbox">{{ lang.mailbox.templates }}</button></li>
</ul> </ul>
</li> </li>
<li class="nav-item" role="presentation"><button class="nav-link" aria-controls="tab-resources" role="tab" data-bs-toggle="tab" data-bs-target="#tab-resources">{{ lang.mailbox.resources }}</button></li> <li class="nav-item" role="presentation"><button class="nav-link" aria-controls="tab-resources" role="tab" data-bs-toggle="tab" data-bs-target="#tab-resources">{{ lang.mailbox.resources }}</button></li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">