Explorar el Código

Merge branch 'dev'

andryyy hace 8 años
padre
commit
26e2baa131

+ 15 - 7
data/Dockerfiles/acme/docker-entrypoint.sh

@@ -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)
 	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..."
-		exit 0
+		sleep 3650d
+		exec $(readlink -f "$0")
 	else
 		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:")
@@ -79,7 +80,8 @@ fi
 while true; do
 	if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
 		echo "SKIP_LETS_ENCRYPT=y, skipping Let's Encrypt..."
-		exit 0
+		sleep 3650d
+		exec $(readlink -f "$0")
 	fi
 	if [[ "${SKIP_IP_CHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
 		SKIP_IP_CHECK=y
@@ -164,8 +166,10 @@ while true; do
   # Unique elements
 	ALL_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs))
 	if [[ -z ${ALL_VALIDATED[*]} ]]; then
-		echo "Cannot validate hostnames, skipping Let's Encrypt..."
-		exit 0
+		echo "Cannot validate hostnames, skipping Let's Encrypt for 1 hour."
+		echo "Use SKIP_LETS_ENCRYPT=y in mailcow.conf to skip it permanently."
+		sleep 1h
+		exec $(readlink -f "$0")
 	fi
 
 	ORPHANED_SAN=($(echo ${SAN_ARRAY_NOW[*]} ${ALL_VALIDATED[*]} | tr ' ' '\n' | sort | uniq -u ))
@@ -219,7 +223,10 @@ while true; do
 				TRIGGER_RESTART=1
 			fi
 			[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
-			exit 1;;
+			echo "Retrying in 30 minutes..."
+			sleep 30m
+			exec $(readlink -f "$0")
+            ;;
 		2) # no change
 			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..."
@@ -253,10 +260,11 @@ while true; do
 				TRIGGER_RESTART=1
 			fi
 			[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
-			exit 1;;
+			sleep 3650d
+			;;
 	esac
 
 	echo "ACME certificate validation done. Sleeping for another day."
-	sleep 86400
+	sleep 1d
 
 done

+ 3 - 3
data/Dockerfiles/rspamd/Dockerfile

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

+ 4 - 4
data/conf/rspamd/dynmaps/settings.php

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

+ 4 - 1
data/web/admin.php

@@ -157,6 +157,7 @@ $tfa_data = get_tfa();
               </div>
               <div class="col-xs-9">
                   <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>
           <?php
@@ -186,6 +187,7 @@ $tfa_data = get_tfa();
                 </div>
                 <div class="col-xs-9">
                   <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>
             <?php
@@ -197,7 +199,7 @@ $tfa_data = get_tfa();
               <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>
               </div>
-            <div class="col-xs-9"><pre>-</pre></div>
+              <div class="col-xs-9"><pre>-</pre></div>
             </div>
             <?php
             }
@@ -217,6 +219,7 @@ $tfa_data = get_tfa();
                 </div>
                 <div class="col-xs-9">
                   <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>
           <?php

+ 13 - 13
data/web/autoconfig.php

@@ -4,7 +4,7 @@ $default_autodiscover_config = $autodiscover_config;
 if(file_exists('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);
 
@@ -33,15 +33,15 @@ header('Content-Type: application/xml');
       <displayShortName>mail server</displayShortName>
 
       <incomingServer type="imap">
-         <hostname><?=$configuration['imap']['server']; ?></hostname>
-         <port><?=$configuration['imap']['port']; ?></port>
+         <hostname><?=$autodiscover_config['imap']['server']; ?></hostname>
+         <port><?=$autodiscover_config['imap']['port']; ?></port>
          <socketType>SSL</socketType>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>
       </incomingServer>
       <incomingServer type="imap">
-         <hostname><?=$configuration['imap']['server']; ?></hostname>
-         <port><?=$configuration['imap']['tlsport']; ?></port>
+         <hostname><?=$autodiscover_config['imap']['server']; ?></hostname>
+         <port><?=$autodiscover_config['imap']['tlsport']; ?></port>
          <socketType>STARTTLS</socketType>
          <username>%EMAILADDRESS%</username>
          <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
 if (count($records) == 0 || $records[0]['target'] != '') { ?>
       <incomingServer type="pop3">
-         <hostname><?=$configuration['pop3']['server']; ?></hostname>
-         <port><?=$configuration['pop3']['port']; ?></port>
+         <hostname><?=$autodiscover_config['pop3']['server']; ?></hostname>
+         <port><?=$autodiscover_config['pop3']['port']; ?></port>
          <socketType>SSL</socketType>
          <username>%EMAILADDRESS%</username>
          <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
 if (count($records) == 0 || $records[0]['target'] != '') { ?>
       <incomingServer type="pop3">
-         <hostname><?=$configuration['pop3']['server']; ?></hostname>
-         <port><?=$configuration['pop3']['tlsport']; ?></port>
+         <hostname><?=$autodiscover_config['pop3']['server']; ?></hostname>
+         <port><?=$autodiscover_config['pop3']['tlsport']; ?></port>
          <socketType>STARTTLS</socketType>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>
@@ -71,15 +71,15 @@ if (count($records) == 0 || $records[0]['target'] != '') { ?>
 <?php } ?>
 
       <outgoingServer type="smtp">
-         <hostname><?=$configuration['smtp']['server']; ?></hostname>
-         <port><?=$configuration['smtp']['port']; ?></port>
+         <hostname><?=$autodiscover_config['smtp']['server']; ?></hostname>
+         <port><?=$autodiscover_config['smtp']['port']; ?></port>
          <socketType>SSL</socketType>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>
       </outgoingServer>
       <outgoingServer type="smtp">
-         <hostname><?=$configuration['smtp']['server']; ?></hostname>
-         <port><?=$configuration['smtp']['tlsport']; ?></port>
+         <hostname><?=$autodiscover_config['smtp']['server']; ?></hostname>
+         <port><?=$autodiscover_config['smtp']['tlsport']; ?></port>
          <socketType>STARTTLS</socketType>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>

+ 14 - 14
data/web/autodiscover.php

@@ -5,7 +5,7 @@ $default_autodiscover_config = $autodiscover_config;
 if(file_exists('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 = 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
 if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { // desktop client
-  $configuration['autodiscoverType'] = 'imap';
-  if ($configuration['useEASforOutlook'] == 'yes' &&
+  $autodiscover_config['autodiscoverType'] = 'imap';
+  if ($autodiscover_config['useEASforOutlook'] == 'yes' &&
     // Office for macOS does not support EAS
     strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false &&
     // Outlook 2013 (version 15) or higher
     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;
       }
 
-      if ($configuration['autodiscoverType'] == 'imap') {
+      if ($autodiscover_config['autodiscoverType'] == 'imap') {
 ?>
   <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
     <User>
@@ -99,8 +99,8 @@ else {
       <Action>settings</Action>
       <Protocol>
         <Type>IMAP</Type>
-        <Server><?=$configuration['imap']['server'];?></Server>
-        <Port><?=$configuration['imap']['port'];?></Port>
+        <Server><?=$autodiscover_config['imap']['server'];?></Server>
+        <Port><?=$autodiscover_config['imap']['port'];?></Port>
         <DomainRequired>off</DomainRequired>
         <LoginName><?=$email;?></LoginName>
         <SPA>off</SPA>
@@ -109,8 +109,8 @@ else {
       </Protocol>
       <Protocol>
         <Type>SMTP</Type>
-        <Server><?=$configuration['smtp']['server'];?></Server>
-        <Port><?=$configuration['smtp']['port'];?></Port>
+        <Server><?=$autodiscover_config['smtp']['server'];?></Server>
+        <Port><?=$autodiscover_config['smtp']['port'];?></Port>
         <DomainRequired>off</DomainRequired>
         <LoginName><?=$email;?></LoginName>
         <SPA>off</SPA>
@@ -121,13 +121,13 @@ else {
       </Protocol>
       <Protocol>
         <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>
         <LoginName><?=$email;?></LoginName>
       </Protocol>
       <Protocol>
         <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>
         <LoginName><?=$email;?></LoginName>
       </Protocol>
@@ -135,7 +135,7 @@ else {
   </Response>
 <?php
       }
-      else if ($configuration['autodiscoverType'] == 'activesync') {
+      else if ($autodiscover_config['autodiscoverType'] == 'activesync') {
 ?>
   <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006">
     <Culture>en:en</Culture>
@@ -147,8 +147,8 @@ else {
       <Settings>
         <Server>
         <Type>MobileSync</Type>
-        <Url><?=$configuration['activesync']['url'];?></Url>
-        <Name><?=$configuration['activesync']['url'];?></Name>
+        <Url><?=$autodiscover_config['activesync']['url'];?></Url>
+        <Name><?=$autodiscover_config['activesync']['url'];?></Name>
         </Server>
       </Settings>
     </Action>

+ 8 - 0
data/web/inc/functions.dkim.inc.php

@@ -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_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;
     break;

+ 3 - 1
data/web/inc/prerequisites.inc.php

@@ -1,8 +1,10 @@
 <?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')) {
   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';
 

+ 3 - 0
data/web/inc/vars.inc.php

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

+ 102 - 0
data/web/js/admin.js

@@ -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($){
   // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
   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) {
     e.preventDefault();
     prev = $('#test_relayhost').text();

+ 1 - 0
data/web/lang/lang.de.php

@@ -108,6 +108,7 @@ $lang['user']['user_settings'] = 'Benutzereinstellungen';
 $lang['user']['mailbox_settings'] = 'Mailbox-Einstellungen';
 $lang['user']['mailbox_details'] = 'Mailbox-Details';
 $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']['save_changes'] = 'Änderungen speichern';
 $lang['user']['password_now'] = 'Aktuelles Passwort (Änderungen bestätigen)';

+ 1 - 0
data/web/lang/lang.en.php

@@ -110,6 +110,7 @@ $lang['user']['user_settings'] = 'User settings';
 $lang['user']['mailbox_settings'] = 'Mailbox settings';
 $lang['user']['mailbox_details'] = 'Mailbox details';
 $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']['save_changes'] = 'Save changes';
 $lang['user']['password_now'] = 'Current password (confirm changes)';

+ 14 - 0
data/web/modals/admin.php

@@ -91,3 +91,17 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
     </div>
   </div>
 </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 -->

+ 20 - 3
data/web/user.php

@@ -60,10 +60,26 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
   / USER
   */
 
-	require_once("inc/header.inc.php");
-	$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
-	$username = $_SESSION['mailcow_cc_username'];
+  require_once("inc/header.inc.php");
+  $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
+  $username = $_SESSION['mailcow_cc_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">
 <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="col-sm-offset-3 col-sm-9">
       <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>
   <hr>

+ 13 - 35
docker-compose.yml

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