[Web] Use INTL_IDNA_VARIANT_UTS46 in idn_to_ascii (thanks to @Knight1 !)

[Web] Some PHP fixes (warnings, notices)
[Web] Add quota notification tools
master
andryyy 2019-02-05 00:10:21 +01:00
parent 21741dc061
commit 1e764009bf
No known key found for this signature in database
GPG Key ID: 8EC34FF2794E25EF
25 changed files with 237 additions and 98 deletions

View File

@ -76,8 +76,8 @@ $tfa_data = get_tfa();
</select> </select>
</div> </div>
</div> </div>
<legend data-target="#api" style="margin-top:40px;cursor:pointer" id="api_legend" unselectable="on" data-toggle="collapse"> <legend data-target="#api" style="margin-top:40px;cursor:pointer" class="arrow-toggle" unselectable="on" data-toggle="collapse">
<span id="api_arrow" style="font-size:12px" class="rotate glyphicon glyphicon-menu-down"></span> API (experimental, work in progress) <span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> API (experimental, work in progress)
</legend> </legend>
<?php <?php
$api = admin_api('get'); $api = admin_api('get');
@ -283,6 +283,7 @@ $tfa_data = get_tfa();
<a href="#fwdhosts" class="list-group-item"><?=$lang['admin']['forwarding_hosts'];?></a> <a href="#fwdhosts" class="list-group-item"><?=$lang['admin']['forwarding_hosts'];?></a>
<a href="#f2bparams" class="list-group-item"><?=$lang['admin']['f2b_parameters'];?></a> <a href="#f2bparams" class="list-group-item"><?=$lang['admin']['f2b_parameters'];?></a>
<a href="#quarantine" class="list-group-item"><?=$lang['admin']['quarantine'];?></a> <a href="#quarantine" class="list-group-item"><?=$lang['admin']['quarantine'];?></a>
<a href="#quota" class="list-group-item">Quota notifications</a>
<a href="#rsettings" class="list-group-item">Rspamd settings map</a> <a href="#rsettings" class="list-group-item">Rspamd settings map</a>
<a href="#customize" class="list-group-item"><?=$lang['admin']['customize'];?></a> <a href="#customize" class="list-group-item"><?=$lang['admin']['customize'];?></a>
<a href="#top" class="list-group-item" style="border-top:1px dashed #dadada"> <?=$lang['admin']['to_top'];?></a> <a href="#top" class="list-group-item" style="border-top:1px dashed #dadada"> <?=$lang['admin']['to_top'];?></a>
@ -415,8 +416,8 @@ $tfa_data = get_tfa();
<button class="btn btn-sm btn-default" data-action="add_item" data-id="dkim" data-api-url='add/dkim' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button> <button class="btn btn-sm btn-default" data-action="add_item" data-id="dkim" data-api-url='add/dkim' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button>
</form> </form>
<legend data-target="#import_dkim" style="margin-top:40px;cursor:pointer" id="import_dkim_legend" unselectable="on" data-toggle="collapse"> <legend data-target="#import_dkim" style="margin-top:40px;cursor:pointer" class="arrow-toggle"" unselectable="on" data-toggle="collapse">
<span id="import_dkim_arrow" style="font-size:12px" class="rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['import_private_key'];?> <span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['import_private_key'];?>
</legend> </legend>
<div id="import_dkim" class="collapse"> <div id="import_dkim" class="collapse">
<form class="form" data-id="dkim_import" role="form" method="post"> <form class="form" data-id="dkim_import" role="form" method="post">
@ -436,8 +437,8 @@ $tfa_data = get_tfa();
</form> </form>
</div> </div>
<legend data-target="#duplicate_dkim" style="margin-top:40px;cursor:pointer" id="duplicate_dkim_legend" unselectable="on" data-toggle="collapse"> <legend data-target="#duplicate_dkim" style="margin-top:40px;cursor:pointer" class="arrow-toggle" unselectable="on" data-toggle="collapse">
<span id="duplicate_dkim_arrow" style="font-size:12px" class="rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['duplicate_dkim'];?> <span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['duplicate_dkim'];?>
</legend> </legend>
<div id="duplicate_dkim" class="collapse"> <div id="duplicate_dkim" class="collapse">
<form class="form-horizontal" data-id="dkim_duplicate" role="form" method="post"> <form class="form-horizontal" data-id="dkim_duplicate" role="form" method="post">
@ -579,32 +580,36 @@ $tfa_data = get_tfa();
<i><?=$lang['admin']['no_active_bans'];?></i> <i><?=$lang['admin']['no_active_bans'];?></i>
<?php <?php
endif; endif;
foreach ($f2b_data['active_bans'] as $active_bans): if (!empty($f2b_data['active_bans'])):
?> foreach ($f2b_data['active_bans'] as $active_bans):
<p><span class="label label-info" style="padding:4px;font-size:85%;"><span class="glyphicon glyphicon-filter"></span> <?=$active_bans['network'];?> (<?=$active_bans['banned_until'];?>) -
<?php
if ($active_bans['queued_for_unban'] == 0):
?> ?>
<a data-action="edit_selected" data-item="<?=$active_bans['network'];?>" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"unban"}' href="#">[<?=$lang['admin']['queue_unban'];?>]</a> <p><span class="label label-info" style="padding:4px;font-size:85%;"><span class="glyphicon glyphicon-filter"></span> <?=$active_bans['network'];?> (<?=$active_bans['banned_until'];?>) -
<a data-action="edit_selected" data-item="<?=$active_bans['network'];?>" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"whitelist"}' href="#">[whitelist]</a> <?php
<a data-action="edit_selected" data-item="<?=$active_bans['network'];?>" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"blacklist"}' href="#">[blacklist]</a> if ($active_bans['queued_for_unban'] == 0):
?>
<a data-action="edit_selected" data-item="<?=$active_bans['network'];?>" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"unban"}' href="#">[<?=$lang['admin']['queue_unban'];?>]</a>
<a data-action="edit_selected" data-item="<?=$active_bans['network'];?>" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"whitelist"}' href="#">[whitelist]</a>
<a data-action="edit_selected" data-item="<?=$active_bans['network'];?>" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"blacklist"}' href="#">[blacklist]</a>
<?php
else:
?>
<i><?=$lang['admin']['unban_pending'];?></i>
<?php
endif;
?>
</span></p>
<?php <?php
else: endforeach;
endif;
if (!empty($f2b_data['perm_bans'])):
foreach ($f2b_data['perm_bans'] as $perm_bans):
?> ?>
<i><?=$lang['admin']['unban_pending'];?></i> <p>
<span class="label label-danger" style="padding:4px;font-size:85%;"><span class="glyphicon glyphicon-filter"></span> <?=$perm_bans?></span>
</p>
<?php <?php
endif; endforeach;
?> endif;
</span></p>
<?php
endforeach;
foreach ($f2b_data['perm_bans'] as $perm_bans):
?>
<p>
<span class="label label-danger" style="padding:4px;font-size:85%;"><span class="glyphicon glyphicon-filter"></span> <?=$perm_bans?></span>
</p>
<?php
endforeach;
?> ?>
</div> </div>
</div> </div>
@ -645,9 +650,12 @@ $tfa_data = get_tfa();
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<label for="html"><?=$lang['admin']['quarantine_notification_html'];?></label> <legend data-target="#quarantine_template" style="cursor:pointer" class="arrow-toggle" unselectable="on" data-toggle="collapse">
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code" rows="20" name="html"><?=$q_data['html'];?></textarea> <span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['quarantine_notification_html'];?>
<br> </legend>
<div id="quarantine_template" class="collapse" >
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code" rows="20" name="html_tmpl"><?=$q_data['html_tmpl'];?></textarea>
</div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -680,13 +688,63 @@ $tfa_data = get_tfa();
</div> </div>
</div> </div>
<span class="anchor" id="quota"></span>
<div class="panel panel-default">
<div class="panel-heading">Quota notifications</div>
<div class="panel-body">
<p>Quota notications are sent to users once when crossing 80% and once when crossing 95% usage.</p>
<?php $q_data = quota_notification('get');?>
<form class="form" role="form" data-id="quota_notification" method="post">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="sender"><?=$lang['admin']['quarantine_notification_sender'];?>:</label>
<input type="text" class="form-control" name="sender" value="<?=$q_data['sender'];?>" placeholder="quota-warning@localhost">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="subject"><?=$lang['admin']['quarantine_notification_subject'];?>:</label>
<input type="text" class="form-control" name="subject" value="<?=$q_data['subject'];?>" placeholder="Quota warning">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<legend data-target="#quota_template" style="cursor:pointer" class="arrow-toggle" unselectable="on" data-toggle="collapse">
<span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['quarantine_notification_html'];?>
</legend>
<div id="quota_template" class="collapse" >
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code collapse in" rows="20" name="html"><?=$q_data['html_tmpl'];?></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-10">
<div class="form-group">
<br>
<a type="button" class="btn btn-sm btn-success" data-action="edit_selected"
data-item="quota_notification"
data-id="quota_notification"
data-api-url='edit/quota_notification'
data-api-attr='{}'><?=$lang['user']['save_changes'];?></a>
</div>
</div>
</div>
</form>
</div>
</div>
<span class="anchor" id="rsettings"></span> <span class="anchor" id="rsettings"></span>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">Rspamd settings map</div> <div class="panel-heading">Rspamd settings map</div>
<div class="panel-body"> <div class="panel-body">
<legend>Active settings map</legend> <legend data-target="#active_settings_map" style="cursor:pointer" class="arrow-toggle" unselectable="on" data-toggle="collapse">
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code" rows="20" name="settings_map" readonly><?=file_get_contents('http://nginx:8081/settings.php');?></textarea> <span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> Active settings map
<hr> </legend>
<div id="active_settings_map" class="collapse" >
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code" rows="20" name="settings_map" readonly><?=file_get_contents('http://nginx:8081/settings.php');?></textarea>
</div>
<?php $rsettings = rsettings('get'); ?> <?php $rsettings = rsettings('get'); ?>
<form class="form" data-id="rsettings" role="form" method="post"> <form class="form" data-id="rsettings" role="form" method="post">
<div class="row"> <div class="row">
@ -836,29 +894,33 @@ $tfa_data = get_tfa();
<button class="btn btn-sm btn-default" type="button" id="add_app_link_row"><?=$lang['admin']['add_row'];?></button> <button class="btn btn-sm btn-default" type="button" id="add_app_link_row"><?=$lang['admin']['add_row'];?></button>
</div></p> </div></p>
</form> </form>
<legend><?=$lang['admin']['ui_texts'];?></legend> <legend data-target="#ui_texts" style="cursor:pointer" class="arrow-toggle" unselectable="on" data-toggle="collapse">
<span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['ui_texts'];?>
</legend>
<div id="ui_texts" class="collapse" >
<?php <?php
$ui_texts = customize('get', 'ui_texts'); $ui_texts = customize('get', 'ui_texts');
?> ?>
<form class="form" data-id="uitexts" role="form" method="post"> <form class="form" data-id="uitexts" role="form" method="post">
<div class="form-group"> <div class="form-group">
<label for="title_name"><?=$lang['admin']['title_name'];?>:</label> <label for="title_name"><?=$lang['admin']['title_name'];?>:</label>
<input type="text" class="form-control" name="title_name" placeholder="mailcow UI" value="<?=$ui_texts['title_name'];?>"> <input type="text" class="form-control" name="title_name" placeholder="mailcow UI" value="<?=$ui_texts['title_name'];?>">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="main_name"><?=$lang['admin']['main_name'];?>:</label> <label for="main_name"><?=$lang['admin']['main_name'];?>:</label>
<input type="text" class="form-control" name="main_name" placeholder="mailcow UI" value="<?=$ui_texts['main_name'];?>"> <input type="text" class="form-control" name="main_name" placeholder="mailcow UI" value="<?=$ui_texts['main_name'];?>">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="apps_name"><?=$lang['admin']['apps_name'];?>:</label> <label for="apps_name"><?=$lang['admin']['apps_name'];?>:</label>
<input type="text" class="form-control" name="apps_name" placeholder="mailcow Apps" value="<?=$ui_texts['apps_name'];?>"> <input type="text" class="form-control" name="apps_name" placeholder="mailcow Apps" value="<?=$ui_texts['apps_name'];?>">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="help_text"><?=$lang['admin']['help_text'];?>:</label> <label for="help_text"><?=$lang['admin']['help_text'];?>:</label>
<textarea class="form-control" id="help_text" name="help_text" rows="7"><?=$ui_texts['help_text'];?></textarea> <textarea class="form-control" id="help_text" name="help_text" rows="7"><?=$ui_texts['help_text'];?></textarea>
</div> </div>
<button class="btn btn-default" data-action="edit_selected" data-item="ui" data-id="uitexts" data-api-url='edit/ui_texts' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button> <button class="btn btn-default" data-action="edit_selected" data-item="ui" data-id="uitexts" data-api-url='edit/ui_texts' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
</form> </form>
</div>
</div> </div>
</div> </div>
</div> </div>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -44,8 +44,8 @@ function bcc($_action, $_data = null, $attr = null) {
); );
return false; return false;
} }
$domain = idn_to_ascii($local_dest); $domain = idn_to_ascii($local_dest, 0, INTL_IDNA_VARIANT_UTS46);
$local_dest_sane = '@' . idn_to_ascii($local_dest); $local_dest_sane = '@' . idn_to_ascii($local_dest, 0, INTL_IDNA_VARIANT_UTS46);
} }
elseif (filter_var($local_dest, FILTER_VALIDATE_EMAIL)) { elseif (filter_var($local_dest, FILTER_VALIDATE_EMAIL)) {
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) {
@ -265,7 +265,7 @@ function recipient_map($_action, $_data = null, $attr = null) {
$new_dest = strtolower(trim($_data['recipient_map_new'])); $new_dest = strtolower(trim($_data['recipient_map_new']));
$active = intval($_data['active']); $active = intval($_data['active']);
if (is_valid_domain_name($old_dest)) { if (is_valid_domain_name($old_dest)) {
$old_dest_sane = '@' . idn_to_ascii($old_dest); $old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46);
} }
elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) { elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) {
$old_dest_sane = $old_dest; $old_dest_sane = $old_dest;
@ -331,7 +331,7 @@ function recipient_map($_action, $_data = null, $attr = null) {
continue; continue;
} }
if (is_valid_domain_name($old_dest)) { if (is_valid_domain_name($old_dest)) {
$old_dest_sane = '@' . idn_to_ascii($old_dest); $old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46);
} }
elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) { elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) {
$old_dest_sane = $old_dest; $old_dest_sane = $old_dest;

View File

@ -32,7 +32,8 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
$containers = json_decode($response, true); $containers = json_decode($response, true);
if (!empty($containers)) { if (!empty($containers)) {
foreach ($containers as $container) { foreach ($containers as $container) {
if ($container['Config']['Labels']['com.docker.compose.service'] == $service_name if (isset($container['Config']['Labels']['com.docker.compose.service'])
&& $container['Config']['Labels']['com.docker.compose.service'] == $service_name
&& $container['Config']['Labels']['com.docker.compose.project'] == strtolower(getenv('COMPOSE_PROJECT_NAME'))) { && $container['Config']['Labels']['com.docker.compose.project'] == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
return trim($container['Id']); return trim($container['Id']);
} }
@ -120,7 +121,8 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
if (!empty($decoded_response)) { if (!empty($decoded_response)) {
if (empty($service_name)) { if (empty($service_name)) {
foreach ($decoded_response as $container) { foreach ($decoded_response as $container) {
if ($container['Config']['Labels']['com.docker.compose.project'] == strtolower(getenv('COMPOSE_PROJECT_NAME'))) { if (isset($container['Config']['Labels']['com.docker.compose.project'])
&& $container['Config']['Labels']['com.docker.compose.project'] == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
unset($container['Config']['Env']); unset($container['Config']['Env']);
$out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State']; $out[$container['Config']['Labels']['com.docker.compose.service']]['State'] = $container['State'];
$out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config']; $out[$container['Config']['Labels']['com.docker.compose.service']]['Config'] = $container['Config'];
@ -128,7 +130,8 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
} }
} }
else { else {
if ($decoded_response['Config']['Labels']['com.docker.compose.project'] == strtolower(getenv('COMPOSE_PROJECT_NAME'))) { if (isset($decoded_response['Config']['Labels']['com.docker.compose.project'])
&& $decoded_response['Config']['Labels']['com.docker.compose.project'] == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
unset($container['Config']['Env']); unset($container['Config']['Env']);
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['State'] = $decoded_response['State']; $out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['State'] = $decoded_response['State'];
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Config'] = $decoded_response['Config']; $out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['Config'] = $decoded_response['Config'];

View File

@ -118,6 +118,7 @@ function fail2ban($_action, $_data = null) {
if (valid_network($network)) { if (valid_network($network)) {
$redis->hSet('F2B_BLACKLIST', $network, 1); $redis->hSet('F2B_BLACKLIST', $network, 1);
$redis->hDel('F2B_WHITELIST', $network, 1); $redis->hDel('F2B_WHITELIST', $network, 1);
$response = docker('post', 'netfilter-mailcow', 'restart');
} }
} }
} }

View File

@ -680,7 +680,7 @@ function is_valid_domain_name($domain_name) {
if (empty($domain_name)) { if (empty($domain_name)) {
return false; return false;
} }
$domain_name = idn_to_ascii($domain_name); $domain_name = idn_to_ascii($domain_name, 0, INTL_IDNA_VARIANT_UTS46);
return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name)
&& preg_match("/^.{1,253}$/", $domain_name) && preg_match("/^.{1,253}$/", $domain_name)
&& preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)); && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name));

View File

@ -322,7 +322,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
); );
return false; return false;
} }
$domain = idn_to_ascii(strtolower(trim($_data['domain']))); $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
$description = $_data['description']; $description = $_data['description'];
$aliases = $_data['aliases']; $aliases = $_data['aliases'];
$mailboxes = $_data['mailboxes']; $mailboxes = $_data['mailboxes'];
@ -493,7 +493,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
if (empty($goto)) { if (empty($goto)) {
continue; continue;
} }
$goto_domain = idn_to_ascii(substr(strstr($goto, '@'), 1)); $goto_domain = idn_to_ascii(substr(strstr($goto, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
$goto_local_part = strstr($goto, '@', true); $goto_local_part = strstr($goto, '@', true);
$goto = $goto_local_part.'@'.$goto_domain; $goto = $goto_local_part.'@'.$goto_domain;
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
@ -531,7 +531,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
if (in_array($address, $gotos)) { if (in_array($address, $gotos)) {
continue; continue;
} }
$domain = idn_to_ascii(substr(strstr($address, '@'), 1)); $domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
$local_part = strstr($address, '@', true); $local_part = strstr($address, '@', true);
$address = $local_part.'@'.$domain; $address = $local_part.'@'.$domain;
$domaindata = mailbox('get', 'domain_details', $domain); $domaindata = mailbox('get', 'domain_details', $domain);
@ -637,7 +637,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$active = intval($_data['active']); $active = intval($_data['active']);
$alias_domains = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['alias_domain'])); $alias_domains = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['alias_domain']));
$alias_domains = array_filter($alias_domains); $alias_domains = array_filter($alias_domains);
$target_domain = idn_to_ascii(strtolower(trim($_data['target_domain']))); $target_domain = idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46);
if (!isset($_SESSION['acl']['alias_domains']) || $_SESSION['acl']['alias_domains'] != "1" ) { if (!isset($_SESSION['acl']['alias_domains']) || $_SESSION['acl']['alias_domains'] != "1" ) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
@ -663,7 +663,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
return false; return false;
} }
foreach ($alias_domains as $i => $alias_domain) { foreach ($alias_domains as $i => $alias_domain) {
$alias_domain = idn_to_ascii(strtolower(trim($alias_domain))); $alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
if (!is_valid_domain_name($alias_domain)) { if (!is_valid_domain_name($alias_domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
@ -735,7 +735,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
break; break;
case 'mailbox': case 'mailbox':
$local_part = strtolower(trim($_data['local_part'])); $local_part = strtolower(trim($_data['local_part']));
$domain = idn_to_ascii(strtolower(trim($_data['domain']))); $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
$username = $local_part . '@' . $domain; $username = $local_part . '@' . $domain;
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) { if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
@ -938,7 +938,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
); );
break; break;
case 'resource': case 'resource':
$domain = idn_to_ascii(strtolower(trim($_data['domain']))); $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
$description = $_data['description']; $description = $_data['description'];
$local_part = preg_replace('/[^\da-z]/i', '', preg_quote($description, '/')); $local_part = preg_replace('/[^\da-z]/i', '', preg_quote($description, '/'));
$name = $local_part . '@' . $domain; $name = $local_part . '@' . $domain;
@ -1056,11 +1056,11 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
case 'alias_domain': case 'alias_domain':
$alias_domains = (array)$_data['alias_domain']; $alias_domains = (array)$_data['alias_domain'];
foreach ($alias_domains as $alias_domain) { foreach ($alias_domains as $alias_domain) {
$alias_domain = idn_to_ascii(strtolower(trim($alias_domain))); $alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
$is_now = mailbox('get', 'alias_domain_details', $alias_domain); $is_now = mailbox('get', 'alias_domain_details', $alias_domain);
if (!empty($is_now)) { if (!empty($is_now)) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int'];
$target_domain = (!empty($_data['target_domain'])) ? idn_to_ascii(strtolower(trim($_data['target_domain']))) : $is_now['target_domain']; $target_domain = (!empty($_data['target_domain'])) ? idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46) : $is_now['target_domain'];
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
@ -1676,7 +1676,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
continue; continue;
} }
if ($is_now['address'] != $address) { if ($is_now['address'] != $address) {
$domain = idn_to_ascii(substr(strstr($address, '@'), 1)); $domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
$local_part = strstr($address, '@', true); $local_part = strstr($address, '@', true);
$address = $local_part.'@'.$domain; $address = $local_part.'@'.$domain;
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
@ -1810,7 +1810,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$domains = $_data['domain']; $domains = $_data['domain'];
} }
foreach ($domains as $domain) { foreach ($domains as $domain) {
$domain = idn_to_ascii($domain); $domain = idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46);
if (!is_valid_domain_name($domain)) { if (!is_valid_domain_name($domain)) {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
'type' => 'danger', 'type' => 'danger',
@ -2887,7 +2887,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
break; break;
case 'domain_details': case 'domain_details':
$domaindata = array(); $domaindata = array();
$_data = idn_to_ascii(strtolower(trim($_data))); $_data = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
return false; return false;
} }
@ -3308,7 +3308,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
); );
continue; continue;
} }
$domain = idn_to_ascii(strtolower(trim($domain))); $domain = idn_to_ascii(strtolower(trim($domain)), 0, INTL_IDNA_VARIANT_UTS46);
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
WHERE `domain` = :domain"); WHERE `domain` = :domain");
$stmt->execute(array(':domain' => $domain)); $stmt->execute(array(':domain' => $domain));

View File

@ -26,7 +26,7 @@ function policy($_action, $_scope, $_data = null) {
); );
return false; return false;
} }
$object = idn_to_ascii(strtolower(trim($object))); $object = idn_to_ascii(strtolower(trim($object)), 0, INTL_IDNA_VARIANT_UTS46);
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
@ -183,7 +183,7 @@ function policy($_action, $_scope, $_data = null) {
); );
continue; continue;
} }
$object = idn_to_ascii(strtolower(trim($object))); $object = idn_to_ascii(strtolower(trim($object)), 0, INTL_IDNA_VARIANT_UTS46);
} }
else { else {
$_SESSION['return'][] = array( $_SESSION['return'][] = array(
@ -277,7 +277,7 @@ function policy($_action, $_scope, $_data = null) {
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
return false; return false;
} }
$_data = idn_to_ascii(strtolower(trim($_data))); $_data = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
} }
// WHITELIST // WHITELIST

View File

@ -83,7 +83,7 @@ function quarantine($_action, $_data = null) {
$max_size = $_data['max_size']; $max_size = $_data['max_size'];
$subject = $_data['subject']; $subject = $_data['subject'];
$sender = $_data['sender']; $sender = $_data['sender'];
$html = $_data['html']; $html = $_data['html_tmpl'];
$exclude_domains = (array)$_data['exclude_domains']; $exclude_domains = (array)$_data['exclude_domains'];
try { try {
$redis->Set('Q_RETENTION_SIZE', intval($retention_size)); $redis->Set('Q_RETENTION_SIZE', intval($retention_size));
@ -436,9 +436,9 @@ function quarantine($_action, $_data = null) {
$settings['release_format'] = $redis->Get('Q_RELEASE_FORMAT'); $settings['release_format'] = $redis->Get('Q_RELEASE_FORMAT');
$settings['subject'] = $redis->Get('Q_SUBJ'); $settings['subject'] = $redis->Get('Q_SUBJ');
$settings['sender'] = $redis->Get('Q_SENDER'); $settings['sender'] = $redis->Get('Q_SENDER');
$settings['html'] = htmlspecialchars($redis->Get('Q_HTML')); $settings['html_tmpl'] = htmlspecialchars($redis->Get('Q_HTML'));
if (empty($settings['html'])) { if (empty($settings['html_tmpl'])) {
$settings['html'] = htmlspecialchars(file_get_contents("/tpls/quarantine.tpl")); $settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quarantine.tpl"));
} }
} }
catch (RedisException $e) { catch (RedisException $e) {

View File

@ -0,0 +1,65 @@
<?php
function quota_notification($_action, $_data = null) {
global $redis;
global $lang;
$_data_log = $_data;
if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'access_denied'
);
return false;
}
switch ($_action) {
case 'edit':
$retention_size = $_data['retention_size'];
if ($_data['release_format'] == 'attachment' || $_data['release_format'] == 'raw') {
$release_format = $_data['release_format'];
}
else {
$release_format = 'raw';
}
$subject = $_data['subject'];
$sender = $_data['sender'];
$html = $_data['html_tmpl'];
try {
$redis->Set('QW_SENDER', $sender);
$redis->Set('QW_SUBJ', $subject);
$redis->Set('QW_HTML', $html);
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e)
);
return false;
}
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => 'saved_settings'
);
break;
case 'get':
try {
$settings['subject'] = $redis->Get('QW_SUBJ');
$settings['sender'] = $redis->Get('QW_SENDER');
$settings['html_tmpl'] = htmlspecialchars($redis->Get('QW_HTML'));
if (empty($settings['html_tmpl'])) {
$settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quota.tpl"));
}
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data_log),
'msg' => array('redis_error', $e)
);
return false;
}
return $settings;
break;
}
}

View File

@ -7,7 +7,7 @@ function tls_policy_maps($_action, $_data = null, $attr = null) {
} }
switch ($_action) { switch ($_action) {
case 'add': case 'add':
$dest = idn_to_ascii(trim($_data['dest'])); $dest = idn_to_ascii(trim($_data['dest']), 0, INTL_IDNA_VARIANT_UTS46);
$policy = strtolower(trim($_data['policy'])); $policy = strtolower(trim($_data['policy']));
$parameters = (isset($_data['parameters']) && !empty($_data['parameters'])) ? $_data['parameters'] : ''; $parameters = (isset($_data['parameters']) && !empty($_data['parameters'])) ? $_data['parameters'] : '';
if (!empty($parameters)) { if (!empty($parameters)) {

View File

@ -7,10 +7,6 @@
<meta name="theme-color" content="#F5D76E"/> <meta name="theme-color" content="#F5D76E"/>
<meta http-equiv="Referrer-Policy" content="same-origin"> <meta http-equiv="Referrer-Policy" content="same-origin">
<title><?=$UI_TEXTS['title_name'];?></title> <title><?=$UI_TEXTS['title_name'];?></title>
<!--[if lt IE 9]>
<script src="/js/html5shiv.min.js"></script>
<script src="/js/respond.min.js"></script>
<![endif]-->
<?php if (strtolower(trim($DEFAULT_THEME)) != "lumen"): ?> <?php if (strtolower(trim($DEFAULT_THEME)) != "lumen"): ?>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.7/<?= strtolower(trim($DEFAULT_THEME)); ?>/bootstrap.min.css"> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.7/<?= strtolower(trim($DEFAULT_THEME)); ?>/bootstrap.min.css">
<?php endif; <?php endif;
@ -117,12 +113,14 @@
<?php <?php
endforeach; endforeach;
$app_links = customize('get', 'app_links'); $app_links = customize('get', 'app_links');
foreach ($app_links as $row) { if ($app_links) {
foreach ($row as $key => $val): foreach ($app_links as $row) {
?> foreach ($row as $key => $val):
?>
<li><a href="<?= htmlspecialchars($val); ?>"><?= htmlspecialchars($key); ?></a></li> <li><a href="<?= htmlspecialchars($val); ?>"><?= htmlspecialchars($key); ?></a></li>
<?php <?php
endforeach; endforeach;
}
} }
?> ?>
</ul> </ul>

View File

@ -157,6 +157,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.address_rewriting.inc.p
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.domain_admin.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.domain_admin.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.admin.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.admin.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.quarantine.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.quarantine.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.quota_notification.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fwdhost.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fwdhost.inc.php';

View File

@ -44,18 +44,18 @@ $autodiscover_config = array(
// The autoconfig service will additionally announce the STARTTLS-enabled ports, specified in the "tlsport" variable. // The autoconfig service will additionally announce the STARTTLS-enabled ports, specified in the "tlsport" variable.
'imap' => array( 'imap' => array(
'server' => $mailcow_hostname, 'server' => $mailcow_hostname,
'port' => array_pop(explode(':', getenv('IMAPS_PORT'))), 'port' => array_key_last(explode(':', getenv('IMAPS_PORT'))),
'tlsport' => array_pop(explode(':', getenv('IMAP_PORT'))), 'tlsport' => array_key_last(explode(':', getenv('IMAP_PORT'))),
), ),
'pop3' => array( 'pop3' => array(
'server' => $mailcow_hostname, 'server' => $mailcow_hostname,
'port' => array_pop(explode(':', getenv('POPS_PORT'))), 'port' => array_key_last(explode(':', getenv('POPS_PORT'))),
'tlsport' => array_pop(explode(':', getenv('POP_PORT'))), 'tlsport' => array_key_last(explode(':', getenv('POP_PORT'))),
), ),
'smtp' => array( 'smtp' => array(
'server' => $mailcow_hostname, 'server' => $mailcow_hostname,
'port' => array_pop(explode(':', getenv('SMTPS_PORT'))), 'port' => array_key_last(explode(':', getenv('SMTPS_PORT'))),
'tlsport' => array_pop(explode(':', getenv('SUBMISSION_PORT'))), 'tlsport' => array_key_last(explode(':', getenv('SUBMISSION_PORT'))),
), ),
'activesync' => array( 'activesync' => array(
'url' => 'https://'.$mailcow_hostname.($https_port == 443 ? '' : ':'.$https_port).'/Microsoft-Server-ActiveSync', 'url' => 'https://'.$mailcow_hostname.($https_port == 443 ? '' : ':'.$https_port).'/Microsoft-Server-ActiveSync',

View File

@ -1161,6 +1161,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "quarantine": case "quarantine":
process_edit_return(quarantine('edit', $attr)); process_edit_return(quarantine('edit', $attr));
break; break;
case "quota_notification":
process_edit_return(quota_notification('edit', $attr));
break;
case "mailq": case "mailq":
process_edit_return(mailq('edit', array_merge(array('qid' => $items), $attr))); process_edit_return(mailq('edit', array_merge(array('qid' => $items), $attr)));
break; break;

View File

@ -642,8 +642,11 @@ $lang['admin']['quarantine_retention_size'] = "Rückhaltungen pro Mailbox:<br><s
$lang['admin']['quarantine_max_size'] = "Maximale Größe in MiB (größere Elemente werden verworfen):<br><small>0 bedeutet <b>nicht</b> unlimitert.</small>"; $lang['admin']['quarantine_max_size'] = "Maximale Größe in MiB (größere Elemente werden verworfen):<br><small>0 bedeutet <b>nicht</b> unlimitert.</small>";
$lang['admin']['quarantine_exclude_domains'] = "Domains und Alias-Domains ausschließen"; $lang['admin']['quarantine_exclude_domains'] = "Domains und Alias-Domains ausschließen";
$lang['admin']['quarantine_notification_sender'] = "Benachrichtigungs-E-Mail Absender"; $lang['admin']['quarantine_notification_sender'] = "Benachrichtigungs-E-Mail Absender";
$lang['admin']['quota_notification_sender'] = "Benachrichtigungs-E-Mail Absender";
$lang['admin']['quarantine_notification_subject'] = "Benachrichtigungs-E-Mail Betreff"; $lang['admin']['quarantine_notification_subject'] = "Benachrichtigungs-E-Mail Betreff";
$lang['admin']['quota_notification_subject'] = "Benachrichtigungs-E-Mail Betreff";
$lang['admin']['quarantine_notification_html'] = "Benachrichtigungs-E-Mail Inhalt:<br><small>Leer lassen, um Standard-Template wiederherzustellen.</small>"; $lang['admin']['quarantine_notification_html'] = "Benachrichtigungs-E-Mail Inhalt:<br><small>Leer lassen, um Standard-Template wiederherzustellen.</small>";
$lang['admin']['quota_notification_html'] = "Benachrichtigungs-E-Mail Inhalt:<br><small>Leer lassen, um Standard-Template wiederherzustellen.</small>";
$lang['admin']['quarantine_release_format'] = "Format freigegebener Mails"; $lang['admin']['quarantine_release_format'] = "Format freigegebener Mails";
$lang['admin']['quarantine_release_format_raw'] = "Unverändertes Original"; $lang['admin']['quarantine_release_format_raw'] = "Unverändertes Original";
$lang['admin']['quarantine_release_format_att'] = "Als Anhang"; $lang['admin']['quarantine_release_format_att'] = "Als Anhang";

View File

@ -682,6 +682,9 @@ $lang['admin']['quarantine_release_format_att'] = "As attachment";
$lang['admin']['quarantine_notification_sender'] = "Notification email sender"; $lang['admin']['quarantine_notification_sender'] = "Notification email sender";
$lang['admin']['quarantine_notification_subject'] = "Notification email subject"; $lang['admin']['quarantine_notification_subject'] = "Notification email subject";
$lang['admin']['quarantine_notification_html'] = "Notification email template:<br><small>Leave empty to restore default template.</small>"; $lang['admin']['quarantine_notification_html'] = "Notification email template:<br><small>Leave empty to restore default template.</small>";
$lang['admin']['quota_notification_sender'] = "Notification email sender";
$lang['admin']['quota_notification_subject'] = "Notification email subject";
$lang['admin']['quota_notification_html'] = "Notification email template:<br><small>Leave empty to restore default template.</small>";
$lang['admin']['ui_texts'] = "UI labels and texts"; $lang['admin']['ui_texts'] = "UI labels and texts";
$lang['admin']['help_text'] = "Override help text below login mask (HTML allowed)"; $lang['admin']['help_text'] = "Override help text below login mask (HTML allowed)";
$lang['admin']['title_name'] = '"mailcow UI" website title'; $lang['admin']['title_name'] = '"mailcow UI" website title';