Merge branch 'dev'

master
andryyy 2017-09-16 23:07:06 +02:00
commit 26e2baa131
15 changed files with 218 additions and 81 deletions

View File

@ -50,7 +50,8 @@ if [[ -f ${ACME_BASE}/cert.pem ]] && [[ -f ${ACME_BASE}/key.pem ]]; then
ISSUER=$(openssl x509 -in ${ACME_BASE}/cert.pem -noout -issuer) ISSUER=$(openssl x509 -in ${ACME_BASE}/cert.pem -noout -issuer)
if [[ ${ISSUER} != *"Let's Encrypt"* && ${ISSUER} != *"mailcow"* ]]; then if [[ ${ISSUER} != *"Let's Encrypt"* && ${ISSUER} != *"mailcow"* ]]; then
echo "Found certificate with issuer other than mailcow snake-oil CA and Let's Encrypt, skipping ACME client..." echo "Found certificate with issuer other than mailcow snake-oil CA and Let's Encrypt, skipping ACME client..."
exit 0 sleep 3650d
exec $(readlink -f "$0")
else else
declare -a SAN_ARRAY_NOW declare -a SAN_ARRAY_NOW
SAN_NAMES=$(openssl x509 -noout -text -in ${ACME_BASE}/cert.pem | awk '/X509v3 Subject Alternative Name/ {getline;gsub(/ /, "", $0); print}' | tr -d "DNS:") SAN_NAMES=$(openssl x509 -noout -text -in ${ACME_BASE}/cert.pem | awk '/X509v3 Subject Alternative Name/ {getline;gsub(/ /, "", $0); print}' | tr -d "DNS:")
@ -79,7 +80,8 @@ fi
while true; do while true; do
if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "SKIP_LETS_ENCRYPT=y, skipping Let's Encrypt..." echo "SKIP_LETS_ENCRYPT=y, skipping Let's Encrypt..."
exit 0 sleep 3650d
exec $(readlink -f "$0")
fi fi
if [[ "${SKIP_IP_CHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then if [[ "${SKIP_IP_CHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
SKIP_IP_CHECK=y SKIP_IP_CHECK=y
@ -164,8 +166,10 @@ while true; do
# Unique elements # Unique elements
ALL_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs)) ALL_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs))
if [[ -z ${ALL_VALIDATED[*]} ]]; then if [[ -z ${ALL_VALIDATED[*]} ]]; then
echo "Cannot validate hostnames, skipping Let's Encrypt..." echo "Cannot validate hostnames, skipping Let's Encrypt for 1 hour."
exit 0 echo "Use SKIP_LETS_ENCRYPT=y in mailcow.conf to skip it permanently."
sleep 1h
exec $(readlink -f "$0")
fi fi
ORPHANED_SAN=($(echo ${SAN_ARRAY_NOW[*]} ${ALL_VALIDATED[*]} | tr ' ' '\n' | sort | uniq -u )) ORPHANED_SAN=($(echo ${SAN_ARRAY_NOW[*]} ${ALL_VALIDATED[*]} | tr ' ' '\n' | sort | uniq -u ))
@ -219,7 +223,10 @@ while true; do
TRIGGER_RESTART=1 TRIGGER_RESTART=1
fi fi
[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]} [[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
exit 1;; echo "Retrying in 30 minutes..."
sleep 30m
exec $(readlink -f "$0")
;;
2) # no change 2) # no change
if ! diff ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem; then if ! diff ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem; then
echo "Certificate was not changed, but active certificate does not match the verified certificate, fixing and restarting containers..." echo "Certificate was not changed, but active certificate does not match the verified certificate, fixing and restarting containers..."
@ -253,10 +260,11 @@ while true; do
TRIGGER_RESTART=1 TRIGGER_RESTART=1
fi fi
[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]} [[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
exit 1;; sleep 3650d
;;
esac esac
echo "ACME certificate validation done. Sleeping for another day." echo "ACME certificate validation done. Sleeping for another day."
sleep 86400 sleep 1d
done done

View File

@ -18,9 +18,9 @@ RUN apt-get update && apt-get install -y \
&& mkdir -p /run/rspamd \ && mkdir -p /run/rspamd \
&& chown _rspamd:_rspamd /run/rspamd && chown _rspamd:_rspamd /run/rspamd
COPY settings.conf /etc/rspamd/modules.d/settings.conf #COPY settings.conf /etc/rspamd/modules.d/settings.conf
COPY ratelimit.lua /usr/share/rspamd/lua/ratelimit.lua #COPY ratelimit.lua /usr/share/rspamd/lua/ratelimit.lua
COPY lua_util.lua /usr/share/rspamd/lib/lua_util.lua #COPY lua_util.lua /usr/share/rspamd/lib/lua_util.lua
COPY docker-entrypoint.sh /docker-entrypoint.sh COPY docker-entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"] ENTRYPOINT ["/docker-entrypoint.sh"]

View File

@ -191,8 +191,8 @@ while ($row = array_shift($rows)) {
$grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN); $grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN);
$value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0]))); $value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0])));
?> ?>
request_header = { header = {
"From" = "(<?=$value_sane;?>)"; "From" = "/(<?=$value_sane;?>)/i";
} }
<?php <?php
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) { if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
@ -283,8 +283,8 @@ while ($row = array_shift($rows)) {
$grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN); $grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN);
$value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0]))); $value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0])));
?> ?>
request_header = { header = {
"From" = "(<?=$value_sane;?>)"; "From" = "/(<?=$value_sane;?>)/i";
} }
<?php <?php
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) { if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {

View File

@ -157,6 +157,7 @@ $tfa_data = get_tfa();
</div> </div>
<div class="col-xs-9"> <div class="col-xs-9">
<pre><?=$dkim['dkim_txt'];?></pre> <pre><?=$dkim['dkim_txt'];?></pre>
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small> Private key</small></p>
</div> </div>
</div> </div>
<?php <?php
@ -186,6 +187,7 @@ $tfa_data = get_tfa();
</div> </div>
<div class="col-xs-9"> <div class="col-xs-9">
<pre><?=$dkim['dkim_txt'];?></pre> <pre><?=$dkim['dkim_txt'];?></pre>
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small> Private key</small></p>
</div> </div>
</div> </div>
<?php <?php
@ -197,7 +199,7 @@ $tfa_data = get_tfa();
<div class="col-xs-1 col-xs-offset-1"> <div class="col-xs-1 col-xs-offset-1">
<p><small> Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p> <p><small> Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
</div> </div>
<div class="col-xs-9"><pre>-</pre></div> <div class="col-xs-9"><pre>-</pre></div>
</div> </div>
<?php <?php
} }
@ -217,6 +219,7 @@ $tfa_data = get_tfa();
</div> </div>
<div class="col-xs-9"> <div class="col-xs-9">
<pre><?=$dkim['dkim_txt'];?></pre> <pre><?=$dkim['dkim_txt'];?></pre>
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small> Private key</small></p>
</div> </div>
</div> </div>
<?php <?php

View File

@ -4,7 +4,7 @@ $default_autodiscover_config = $autodiscover_config;
if(file_exists('inc/vars.local.inc.php')) { if(file_exists('inc/vars.local.inc.php')) {
include_once 'inc/vars.local.inc.php'; include_once 'inc/vars.local.inc.php';
} }
$configuration = array_merge($default_autodiscover_config, $autodiscover_config); $autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
error_reporting(0); error_reporting(0);
@ -33,15 +33,15 @@ header('Content-Type: application/xml');
<displayShortName>mail server</displayShortName> <displayShortName>mail server</displayShortName>
<incomingServer type="imap"> <incomingServer type="imap">
<hostname><?=$configuration['imap']['server']; ?></hostname> <hostname><?=$autodiscover_config['imap']['server']; ?></hostname>
<port><?=$configuration['imap']['port']; ?></port> <port><?=$autodiscover_config['imap']['port']; ?></port>
<socketType>SSL</socketType> <socketType>SSL</socketType>
<username>%EMAILADDRESS%</username> <username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication> <authentication>password-cleartext</authentication>
</incomingServer> </incomingServer>
<incomingServer type="imap"> <incomingServer type="imap">
<hostname><?=$configuration['imap']['server']; ?></hostname> <hostname><?=$autodiscover_config['imap']['server']; ?></hostname>
<port><?=$configuration['imap']['tlsport']; ?></port> <port><?=$autodiscover_config['imap']['tlsport']; ?></port>
<socketType>STARTTLS</socketType> <socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username> <username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication> <authentication>password-cleartext</authentication>
@ -51,8 +51,8 @@ header('Content-Type: application/xml');
$records = dns_get_record('_pop3s._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record $records = dns_get_record('_pop3s._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record
if (count($records) == 0 || $records[0]['target'] != '') { ?> if (count($records) == 0 || $records[0]['target'] != '') { ?>
<incomingServer type="pop3"> <incomingServer type="pop3">
<hostname><?=$configuration['pop3']['server']; ?></hostname> <hostname><?=$autodiscover_config['pop3']['server']; ?></hostname>
<port><?=$configuration['pop3']['port']; ?></port> <port><?=$autodiscover_config['pop3']['port']; ?></port>
<socketType>SSL</socketType> <socketType>SSL</socketType>
<username>%EMAILADDRESS%</username> <username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication> <authentication>password-cleartext</authentication>
@ -62,8 +62,8 @@ if (count($records) == 0 || $records[0]['target'] != '') { ?>
$records = dns_get_record('_pop3._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record $records = dns_get_record('_pop3._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record
if (count($records) == 0 || $records[0]['target'] != '') { ?> if (count($records) == 0 || $records[0]['target'] != '') { ?>
<incomingServer type="pop3"> <incomingServer type="pop3">
<hostname><?=$configuration['pop3']['server']; ?></hostname> <hostname><?=$autodiscover_config['pop3']['server']; ?></hostname>
<port><?=$configuration['pop3']['tlsport']; ?></port> <port><?=$autodiscover_config['pop3']['tlsport']; ?></port>
<socketType>STARTTLS</socketType> <socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username> <username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication> <authentication>password-cleartext</authentication>
@ -71,15 +71,15 @@ if (count($records) == 0 || $records[0]['target'] != '') { ?>
<?php } ?> <?php } ?>
<outgoingServer type="smtp"> <outgoingServer type="smtp">
<hostname><?=$configuration['smtp']['server']; ?></hostname> <hostname><?=$autodiscover_config['smtp']['server']; ?></hostname>
<port><?=$configuration['smtp']['port']; ?></port> <port><?=$autodiscover_config['smtp']['port']; ?></port>
<socketType>SSL</socketType> <socketType>SSL</socketType>
<username>%EMAILADDRESS%</username> <username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication> <authentication>password-cleartext</authentication>
</outgoingServer> </outgoingServer>
<outgoingServer type="smtp"> <outgoingServer type="smtp">
<hostname><?=$configuration['smtp']['server']; ?></hostname> <hostname><?=$autodiscover_config['smtp']['server']; ?></hostname>
<port><?=$configuration['smtp']['tlsport']; ?></port> <port><?=$autodiscover_config['smtp']['tlsport']; ?></port>
<socketType>STARTTLS</socketType> <socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username> <username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication> <authentication>password-cleartext</authentication>

View File

@ -5,7 +5,7 @@ $default_autodiscover_config = $autodiscover_config;
if(file_exists('inc/vars.local.inc.php')) { if(file_exists('inc/vars.local.inc.php')) {
include_once 'inc/vars.local.inc.php'; include_once 'inc/vars.local.inc.php';
} }
$configuration = array_merge($default_autodiscover_config, $autodiscover_config); $autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
// Redis // Redis
$redis = new Redis(); $redis = new Redis();
@ -17,14 +17,14 @@ $data = trim(file_get_contents("php://input"));
// Desktop client needs IMAP, unless it's Outlook 2013 or higher on Windows // Desktop client needs IMAP, unless it's Outlook 2013 or higher on Windows
if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { // desktop client if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { // desktop client
$configuration['autodiscoverType'] = 'imap'; $autodiscover_config['autodiscoverType'] = 'imap';
if ($configuration['useEASforOutlook'] == 'yes' && if ($autodiscover_config['useEASforOutlook'] == 'yes' &&
// Office for macOS does not support EAS // Office for macOS does not support EAS
strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false && strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false &&
// Outlook 2013 (version 15) or higher // Outlook 2013 (version 15) or higher
preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT']) preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT'])
) { ) {
$configuration['autodiscoverType'] = 'activesync'; $autodiscover_config['autodiscoverType'] = 'activesync';
} }
} }
@ -88,7 +88,7 @@ else {
$displayname = $email; $displayname = $email;
} }
if ($configuration['autodiscoverType'] == 'imap') { if ($autodiscover_config['autodiscoverType'] == 'imap') {
?> ?>
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a"> <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
<User> <User>
@ -99,8 +99,8 @@ else {
<Action>settings</Action> <Action>settings</Action>
<Protocol> <Protocol>
<Type>IMAP</Type> <Type>IMAP</Type>
<Server><?=$configuration['imap']['server'];?></Server> <Server><?=$autodiscover_config['imap']['server'];?></Server>
<Port><?=$configuration['imap']['port'];?></Port> <Port><?=$autodiscover_config['imap']['port'];?></Port>
<DomainRequired>off</DomainRequired> <DomainRequired>off</DomainRequired>
<LoginName><?=$email;?></LoginName> <LoginName><?=$email;?></LoginName>
<SPA>off</SPA> <SPA>off</SPA>
@ -109,8 +109,8 @@ else {
</Protocol> </Protocol>
<Protocol> <Protocol>
<Type>SMTP</Type> <Type>SMTP</Type>
<Server><?=$configuration['smtp']['server'];?></Server> <Server><?=$autodiscover_config['smtp']['server'];?></Server>
<Port><?=$configuration['smtp']['port'];?></Port> <Port><?=$autodiscover_config['smtp']['port'];?></Port>
<DomainRequired>off</DomainRequired> <DomainRequired>off</DomainRequired>
<LoginName><?=$email;?></LoginName> <LoginName><?=$email;?></LoginName>
<SPA>off</SPA> <SPA>off</SPA>
@ -121,13 +121,13 @@ else {
</Protocol> </Protocol>
<Protocol> <Protocol>
<Type>CalDAV</Type> <Type>CalDAV</Type>
<Server>https://<?=$configuration['caldav']['server'];?><?php if ($configuration['caldav']['port'] != 443) echo ':'.$configuration['caldav']['port']; ?>/SOGo/dav/<?=$email;?>/Calendar</Server> <Server>https://<?=$autodiscover_config['caldav']['server'];?><?php if ($autodiscover_config['caldav']['port'] != 443) echo ':'.$autodiscover_config['caldav']['port']; ?>/SOGo/dav/<?=$email;?>/Calendar</Server>
<DomainRequired>off</DomainRequired> <DomainRequired>off</DomainRequired>
<LoginName><?=$email;?></LoginName> <LoginName><?=$email;?></LoginName>
</Protocol> </Protocol>
<Protocol> <Protocol>
<Type>CardDAV</Type> <Type>CardDAV</Type>
<Server>https://<?=$configuration['carddav']['server'];?><?php if ($configuration['caldav']['port'] != 443) echo ':'.$configuration['carddav']['port']; ?>/SOGo/dav/<?=$email;?>/Contacts</Server> <Server>https://<?=$autodiscover_config['carddav']['server'];?><?php if ($autodiscover_config['caldav']['port'] != 443) echo ':'.$autodiscover_config['carddav']['port']; ?>/SOGo/dav/<?=$email;?>/Contacts</Server>
<DomainRequired>off</DomainRequired> <DomainRequired>off</DomainRequired>
<LoginName><?=$email;?></LoginName> <LoginName><?=$email;?></LoginName>
</Protocol> </Protocol>
@ -135,7 +135,7 @@ else {
</Response> </Response>
<?php <?php
} }
else if ($configuration['autodiscoverType'] == 'activesync') { else if ($autodiscover_config['autodiscoverType'] == 'activesync') {
?> ?>
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006"> <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006">
<Culture>en:en</Culture> <Culture>en:en</Culture>
@ -147,8 +147,8 @@ else {
<Settings> <Settings>
<Server> <Server>
<Type>MobileSync</Type> <Type>MobileSync</Type>
<Url><?=$configuration['activesync']['url'];?></Url> <Url><?=$autodiscover_config['activesync']['url'];?></Url>
<Name><?=$configuration['activesync']['url'];?></Name> <Name><?=$autodiscover_config['activesync']['url'];?></Name>
</Server> </Server>
</Settings> </Settings>
</Action> </Action>

View File

@ -187,6 +187,14 @@ function dkim($_action, $_data = null) {
} }
$dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data; $dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data;
$dkimdata['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $_data); $dkimdata['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $_data);
$dkimdata['privkey'] = $redis->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . $_data);
if ($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) {
$dkimdata['privkey'] = base64_encode($redis->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . '.' . $_data));
}
else {
$dkimdata['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
}
} }
return $dkimdata; return $dkimdata;
break; break;

View File

@ -1,8 +1,10 @@
<?php <?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php'; require_once 'inc/vars.inc.php';
$default_autodiscover_config = $autodiscover_config;
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) { if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
include_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php'; include_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php';
} }
$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';

View File

@ -82,6 +82,9 @@ $DEFAULT_THEME = 'lumen';
// Password complexity as regular expression // Password complexity as regular expression
$PASSWD_REGEP = '.{4,}'; $PASSWD_REGEP = '.{4,}';
// Show DKIM private keys - false by default
$SHOW_DKIM_PRIV_KEYS = false;
// mailcow Apps - buttons on login screen // mailcow Apps - buttons on login screen
$MAILCOW_APPS = array( $MAILCOW_APPS = array(
array( array(

View File

@ -1,3 +1,96 @@
var Base64 = {
_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
encode: function(e) {
var t = "";
var n, r, i, s, o, u, a;
var f = 0;
e = Base64._utf8_encode(e);
while (f < e.length) {
n = e.charCodeAt(f++);
r = e.charCodeAt(f++);
i = e.charCodeAt(f++);
s = n >> 2;
o = (n & 3) << 4 | r >> 4;
u = (r & 15) << 2 | i >> 6;
a = i & 63;
if (isNaN(r)) {
u = a = 64
} else if (isNaN(i)) {
a = 64
}
t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) +
this._keyStr.charAt(u) + this._keyStr.charAt(a)
}
return t
},
decode: function(e) {
var t = "";
var n, r, i;
var s, o, u, a;
var f = 0;
e = e.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (f < e.length) {
s = this._keyStr.indexOf(e.charAt(f++));
o = this._keyStr.indexOf(e.charAt(f++));
u = this._keyStr.indexOf(e.charAt(f++));
a = this._keyStr.indexOf(e.charAt(f++));
n = s << 2 | o >> 4;
r = (o & 15) << 4 | u >> 2;
i = (u & 3) << 6 | a;
t = t + String.fromCharCode(n);
if (u != 64) {
t = t + String.fromCharCode(r)
}
if (a != 64) {
t = t + String.fromCharCode(i)
}
}
t = Base64._utf8_decode(t);
return t
},
_utf8_encode: function(e) {
e = e.replace(/\r\n/g, "\n");
var t = "";
for (var n = 0; n < e.length; n++) {
var r = e.charCodeAt(n);
if (r < 128) {
t += String.fromCharCode(r)
} else if (r > 127 && r < 2048) {
t += String.fromCharCode(r >> 6 | 192);
t += String.fromCharCode(r & 63 | 128)
} else {
t += String.fromCharCode(r >> 12 | 224);
t += String.fromCharCode(r >> 6 & 63 | 128);
t += String.fromCharCode(r & 63 | 128)
}
}
return t
},
_utf8_decode: function(e) {
var t = "";
var n = 0;
var r = c1 = c2 = 0;
while (n < e.length) {
r = e.charCodeAt(n);
if (r < 128) {
t += String.fromCharCode(r);
n++
} else if (r > 191 && r < 224) {
c2 = e.charCodeAt(n + 1);
t += String.fromCharCode((r & 31) << 6 | c2 & 63);
n += 2
} else {
c2 = e.charCodeAt(n + 1);
c3 = e.charCodeAt(n + 2);
t += String.fromCharCode((r & 15) << 12 | (c2 & 63) <<
6 | c3 & 63);
n += 3
}
}
return t
}
}
jQuery(function($){ jQuery(function($){
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
var entityMap = { var entityMap = {
@ -560,6 +653,15 @@ jQuery(function($){
} }
}) })
$('#showDKIMprivKey').on('show.bs.modal', function (e) {
$('#priv_key_pre').text("-");
p_related = $(e.relatedTarget)
if (p_related != null) {
var decoded_key = Base64.decode((p_related.data('priv-key')));
$('#priv_key_pre').text(decoded_key);
}
})
$('#test_relayhost').on('click', function (e) { $('#test_relayhost').on('click', function (e) {
e.preventDefault(); e.preventDefault();
prev = $('#test_relayhost').text(); prev = $('#test_relayhost').text();

View File

@ -108,6 +108,7 @@ $lang['user']['user_settings'] = 'Benutzereinstellungen';
$lang['user']['mailbox_settings'] = 'Mailbox-Einstellungen'; $lang['user']['mailbox_settings'] = 'Mailbox-Einstellungen';
$lang['user']['mailbox_details'] = 'Mailbox-Details'; $lang['user']['mailbox_details'] = 'Mailbox-Details';
$lang['user']['change_password'] = 'Passwort ändern'; $lang['user']['change_password'] = 'Passwort ändern';
$lang['user']['client_configuration'] = 'Konfigurationsanleitungen für E-Mail-Programme und Smartphones anzeigen';
$lang['user']['new_password'] = 'Neues Passwort'; $lang['user']['new_password'] = 'Neues Passwort';
$lang['user']['save_changes'] = 'Änderungen speichern'; $lang['user']['save_changes'] = 'Änderungen speichern';
$lang['user']['password_now'] = 'Aktuelles Passwort (Änderungen bestätigen)'; $lang['user']['password_now'] = 'Aktuelles Passwort (Änderungen bestätigen)';

View File

@ -110,6 +110,7 @@ $lang['user']['user_settings'] = 'User settings';
$lang['user']['mailbox_settings'] = 'Mailbox settings'; $lang['user']['mailbox_settings'] = 'Mailbox settings';
$lang['user']['mailbox_details'] = 'Mailbox details'; $lang['user']['mailbox_details'] = 'Mailbox details';
$lang['user']['change_password'] = 'Change password'; $lang['user']['change_password'] = 'Change password';
$lang['user']['client_configuration'] = 'Show configuration guides for email clients and smartphones';
$lang['user']['new_password'] = 'New password'; $lang['user']['new_password'] = 'New password';
$lang['user']['save_changes'] = 'Save changes'; $lang['user']['save_changes'] = 'Save changes';
$lang['user']['password_now'] = 'Current password (confirm changes)'; $lang['user']['password_now'] = 'Current password (confirm changes)';

View File

@ -91,3 +91,17 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
</div> </div>
</div> </div>
</div><!-- test relayhost modal --> </div><!-- test relayhost modal -->
<!-- priv key modal -->
<div class="modal fade" id="showDKIMprivKey" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><span class="glyphicon glyphicon-lock"></span> Private key</h3>
</div>
<div class="modal-body">
<pre id="priv_key_pre"></pre>
</div>
</div>
</div>
</div><!-- priv key modal -->

View File

@ -60,10 +60,26 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
/ USER / USER
*/ */
require_once("inc/header.inc.php"); require_once("inc/header.inc.php");
$_SESSION['return_to'] = $_SERVER['REQUEST_URI']; $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$username = $_SESSION['mailcow_cc_username']; $username = $_SESSION['mailcow_cc_username'];
$mailboxdata = mailbox('get', 'mailbox_details', $username); $mailboxdata = mailbox('get', 'mailbox_details', $username);
$clientconfigstr = "host=" . urlencode($mailcow_hostname) . "&email=" . urlencode($username) . "&name=" . urlencode($mailboxdata['name']) . "&port=" . urlencode($autodiscover_config['caldav']['port']);
if ($autodiscover_config['useEASforOutlook'] == 'yes')
$clientconfigstr .= "&outlookEAS=1";
if (file_exists('thunderbird-plugins/version.csv')) {
$fh = fopen('thunderbird-plugins/version.csv', 'r');
if ($fh) {
while (($row = fgetcsv($fh, 1000, ';')) !== FALSE) {
if ($row[0] == 'sogo-integrator@inverse.ca') {
$clientconfigstr .= "&integrator=" . urlencode($row[1]);
}
}
fclose($fh);
}
}
?> ?>
<div class="container"> <div class="container">
<h3><?=$lang['user']['user_settings'];?></h3> <h3><?=$lang['user']['user_settings'];?></h3>
@ -74,6 +90,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
<div class="row"> <div class="row">
<div class="col-sm-offset-3 col-sm-9"> <div class="col-sm-offset-3 col-sm-9">
<p><a href="#pwChangeModal" data-toggle="modal">[<?=$lang['user']['change_password'];?>]</a></p> <p><a href="#pwChangeModal" data-toggle="modal">[<?=$lang['user']['change_password'];?>]</a></p>
<p><a target="_blank" href="https://mailcow.github.io/mailcow-dockerized-docs/client/#<?=$clientconfigstr;?>">[<?=$lang['user']['client_configuration'];?>]</a></p>
</div> </div>
</div> </div>
<hr> <hr>

View File

@ -1,18 +1,14 @@
version: '2.1' version: '2.3'
services: services:
unbound-mailcow: unbound-mailcow:
image: mailcow/unbound:1.0 image: mailcow/unbound:1.0
build: ./data/Dockerfiles/unbound build: ./data/Dockerfiles/unbound
command: /usr/sbin/unbound command: /usr/sbin/unbound
init: true
depends_on: depends_on:
mysql-mailcow: mysql-mailcow:
condition: service_healthy condition: service_healthy
healthcheck:
test: ["CMD", "nslookup", "mailcow.email", "127.0.0.1"]
interval: 30s
timeout: 3s
retries: 10
volumes: volumes:
- ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro - ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro
restart: always restart: always
@ -38,6 +34,7 @@ services:
- MYSQL_DATABASE=${DBNAME} - MYSQL_DATABASE=${DBNAME}
- MYSQL_USER=${DBUSER} - MYSQL_USER=${DBUSER}
- MYSQL_PASSWORD=${DBPASS} - MYSQL_PASSWORD=${DBPASS}
init: true
restart: always restart: always
dns: dns:
- 172.22.1.254 - 172.22.1.254
@ -50,9 +47,6 @@ services:
redis-mailcow: redis-mailcow:
image: redis:alpine image: redis:alpine
depends_on:
unbound-mailcow:
condition: service_healthy
volumes: volumes:
- redis-vol-1:/data/ - redis-vol-1:/data/
restart: always restart: always
@ -66,11 +60,12 @@ services:
- redis - redis
clamd-mailcow: clamd-mailcow:
image: mailcow/clamd:1.2 image: mailcow/clamd:1.3
build: ./data/Dockerfiles/clamd build: ./data/Dockerfiles/clamd
restart: on-failure restart: on-failure
environment: environment:
- SKIP_CLAMD=${SKIP_CLAMD:-n} - SKIP_CLAMD=${SKIP_CLAMD:-n}
init: true
dns: dns:
- 172.22.1.254 - 172.22.1.254
dns_search: mailcow-network dns_search: mailcow-network
@ -80,13 +75,9 @@ services:
- clamd - clamd
rspamd-mailcow: rspamd-mailcow:
image: mailcow/rspamd:1.6 image: mailcow/rspamd:1.7
build: ./data/Dockerfiles/rspamd build: ./data/Dockerfiles/rspamd
command: > command: "/usr/bin/rspamd -f -u _rspamd -g _rspamd"
/bin/bash -c "
sleep 5;
/usr/bin/rspamd -f -u _rspamd -g _rspamd
"
depends_on: depends_on:
- nginx-mailcow - nginx-mailcow
volumes: volumes:
@ -97,6 +88,7 @@ services:
- dkim-vol-1:/data/dkim - dkim-vol-1:/data/dkim
- rspamd-vol-1:/var/lib/rspamd - rspamd-vol-1:/var/lib/rspamd
restart: always restart: always
init: true
dns: dns:
- 172.22.1.254 - 172.22.1.254
dns_search: mailcow-network dns_search: mailcow-network
@ -142,9 +134,6 @@ services:
sogo-mailcow: sogo-mailcow:
image: mailcow/sogo:1.8 image: mailcow/sogo:1.8
build: ./data/Dockerfiles/sogo build: ./data/Dockerfiles/sogo
depends_on:
unbound-mailcow:
condition: service_healthy
environment: environment:
- DBNAME=${DBNAME} - DBNAME=${DBNAME}
- DBUSER=${DBUSER} - DBUSER=${DBUSER}
@ -166,9 +155,6 @@ services:
dovecot-mailcow: dovecot-mailcow:
image: mailcow/dovecot:1.8 image: mailcow/dovecot:1.8
build: ./data/Dockerfiles/dovecot build: ./data/Dockerfiles/dovecot
depends_on:
unbound-mailcow:
condition: service_healthy
volumes: volumes:
- ./data/conf/dovecot:/usr/local/etc/dovecot - ./data/conf/dovecot:/usr/local/etc/dovecot
- ./data/assets/ssl:/etc/ssl/mail/:ro - ./data/assets/ssl:/etc/ssl/mail/:ro
@ -204,9 +190,6 @@ services:
postfix-mailcow: postfix-mailcow:
image: mailcow/postfix:1.4 image: mailcow/postfix:1.4
build: ./data/Dockerfiles/postfix build: ./data/Dockerfiles/postfix
depends_on:
unbound-mailcow:
condition: service_healthy
volumes: volumes:
- ./data/conf/postfix:/opt/postfix/conf - ./data/conf/postfix:/opt/postfix/conf
- ./data/assets/ssl:/etc/ssl/mail/:ro - ./data/assets/ssl:/etc/ssl/mail/:ro
@ -232,9 +215,6 @@ services:
memcached-mailcow: memcached-mailcow:
image: memcached:alpine image: memcached:alpine
depends_on:
unbound-mailcow:
condition: service_healthy
restart: always restart: always
dns: dns:
- 172.22.1.254 - 172.22.1.254
@ -249,15 +229,11 @@ services:
- sogo-mailcow - sogo-mailcow
- php-fpm-mailcow - php-fpm-mailcow
image: nginx:mainline-alpine image: nginx:mainline-alpine
healthcheck:
test: ["CMD", "ping", "php-fpm-mailcow", "-c", "5"]
interval: 5s
timeout: 5s
retries: 10
command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active && command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active &&
envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active && envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active &&
envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active && envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active &&
nginx -g 'daemon off;'" until ping phpfpm -c1 > /dev/null; do sleep 1; done &&
exec nginx -g 'daemon off;'"
environment: environment:
- HTTPS_PORT=${HTTPS_PORT:-443} - HTTPS_PORT=${HTTPS_PORT:-443}
- HTTP_PORT=${HTTP_PORT:-80} - HTTP_PORT=${HTTP_PORT:-80}
@ -283,8 +259,9 @@ services:
acme-mailcow: acme-mailcow:
depends_on: depends_on:
- nginx-mailcow - nginx-mailcow
image: mailcow/acme:1.16 image: mailcow/acme:1.17
build: ./data/Dockerfiles/acme build: ./data/Dockerfiles/acme
init: true
dns: dns:
- 172.22.1.254 - 172.22.1.254
dns_search: mailcow-network dns_search: mailcow-network
@ -319,6 +296,7 @@ services:
- redis-mailcow - redis-mailcow
restart: always restart: always
privileged: true privileged: true
init: true
environment: environment:
- TZ=${TZ} - TZ=${TZ}
- SKIP_FAIL2BAN=${SKIP_FAIL2BAN:-no} - SKIP_FAIL2BAN=${SKIP_FAIL2BAN:-no}