From 1fcecd0350a894083f8e40405df1379c843fdd1b Mon Sep 17 00:00:00 2001
From: andryyy <andre.peters@debinux.de>
Date: Mon, 18 Mar 2019 10:16:33 +0100
Subject: [PATCH 1/5] [Web] Fix js when adding resource [Web] Reload view and
 memcached when changing a resource

---
 data/web/inc/functions.mailbox.inc.php |  2 +-
 data/web/js/site/mailbox.js            | 20 +++++++++++++++++++-
 data/web/modals/mailbox.php            | 21 ---------------------
 3 files changed, 20 insertions(+), 23 deletions(-)

diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php
index d479f125..b9129f83 100644
--- a/data/web/inc/functions.mailbox.inc.php
+++ b/data/web/inc/functions.mailbox.inc.php
@@ -3714,7 +3714,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
       }
     break;
   }
-  if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'mailbox'))) {
+  if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'mailbox', 'resource'))) {
     update_sogo_static_view();
   }
 }
diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js
index 674d6703..f8aacac7 100644
--- a/data/web/js/site/mailbox.js
+++ b/data/web/js/site/mailbox.js
@@ -169,7 +169,25 @@ $(document).ready(function() {
     // $("#active-script").closest('td').css('background-color','#b0f0a0');
     // $("#inactive-script").closest('td').css('background-color','#b0f0a0');
   // });
-
+  $('#addResourceModal').on('shown.bs.modal', function() {
+    $("#multiple_bookings").val($("#multiple_bookings_select").val());
+    if ($("#multiple_bookings").val() == "custom") {
+      $("#multiple_bookings_custom_div").show();
+      $("#multiple_bookings").val($("#multiple_bookings_custom").val());
+    }
+  })
+  $("#multiple_bookings_select").change(function() {
+    $("#multiple_bookings").val($("#multiple_bookings_select").val());
+    if ($("#multiple_bookings").val() == "custom") {
+      $("#multiple_bookings_custom_div").show();
+    }
+    else {
+      $("#multiple_bookings_custom_div").hide();
+    }
+  });
+  $("#multiple_bookings_custom").bind ("change keypress keyup blur", function () {
+    $("#multiple_bookings").val($("#multiple_bookings_custom").val());
+  });
 
 
 });
diff --git a/data/web/modals/mailbox.php b/data/web/modals/mailbox.php
index c12df381..11abbc58 100644
--- a/data/web/modals/mailbox.php
+++ b/data/web/modals/mailbox.php
@@ -785,24 +785,3 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
     </div>
   </div>
 </div><!-- DNS info modal -->
-<script>
-$('#addResourceModal').on('shown.bs.modal', function() {
-  $("#multiple_bookings").val($("#multiple_bookings_select").val());
-  if ($("#multiple_bookings").val() == "custom") {
-    $("#multiple_bookings_custom_div").show();
-    $("#multiple_bookings").val($("#multiple_bookings_custom").val());
-  }
-})
-$("#multiple_bookings_select").change(function() {
-  $("#multiple_bookings").val($("#multiple_bookings_select").val());
-  if ($("#multiple_bookings").val() == "custom") {
-    $("#multiple_bookings_custom_div").show();
-  }
-  else {
-    $("#multiple_bookings_custom_div").hide();
-  }
-});
-$("#multiple_bookings_custom").bind ("change keypress keyup blur", function () {
-  $("#multiple_bookings").val($("#multiple_bookings_custom").val());
-});
-</script>

From 22798a85e503a15e6e8203379450eedc42d91a64 Mon Sep 17 00:00:00 2001
From: andryyy <andre.peters@debinux.de>
Date: Mon, 18 Mar 2019 14:09:32 +0100
Subject: [PATCH 2/5] [Config] Add MAILDIR_SUB, "Maildir" for new setups by
 default [Update] Add MAILDIR_SUB= for updated mailcows [Dovecot] Read
 MAILDIR_SUB for mail_home

---
 data/Dockerfiles/dovecot/docker-entrypoint.sh | 2 +-
 docker-compose.yml                            | 3 ++-
 generate_config.sh                            | 3 +++
 update.sh                                     | 6 ++++++
 4 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh
index 80db4b48..e3626938 100755
--- a/data/Dockerfiles/dovecot/docker-entrypoint.sh
+++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh
@@ -106,7 +106,7 @@ chmod 644 /usr/local/etc/dovecot/mail_plugins /usr/local/etc/dovecot/mail_plugin
 cat <<EOF > /usr/local/etc/dovecot/sql/dovecot-dict-sql-userdb.conf
 driver = mysql
 connect = "host=/var/run/mysqld/mysqld.sock dbname=${DBNAME} user=${DBUSER} password=${DBPASS}"
-user_query = SELECT CONCAT(JSON_UNQUOTE(JSON_EXTRACT(attributes, '$.mailbox_format')), mailbox_path_prefix, '%d/%n/:VOLATILEDIR=/var/volatile/%u') AS mail, 5000 AS uid, 5000 AS gid, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1'
+user_query = SELECT CONCAT(JSON_UNQUOTE(JSON_EXTRACT(attributes, '$.mailbox_format')), mailbox_path_prefix, '%d/%n/${MAILDIR_SUB}:VOLATILEDIR=/var/volatile/%u') AS mail, 5000 AS uid, 5000 AS gid, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1'
 iterate_query = SELECT username FROM mailbox WHERE active='1';
 EOF
 
diff --git a/docker-compose.yml b/docker-compose.yml
index 49c784eb..302adf12 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -164,7 +164,7 @@ services:
             - sogo
 
     dovecot-mailcow:
-      image: mailcow/dovecot:1.64
+      image: mailcow/dovecot:1.65
       build: ./data/Dockerfiles/dovecot
       cap_add:
         - NET_BIND_SERVICE
@@ -188,6 +188,7 @@ services:
         - MAILDIR_GC_TIME=${MAILDIR_GC_TIME:-1440}
         - ACL_ANYONE=${ACL_ANYONE:-disallow}
         - SKIP_SOLR=${SKIP_SOLR:-y}
+        - MAILDIR_SUB=${MAILDIR_SUB:-}
       ports:
         - "${DOVEADM_PORT:-127.0.0.1:19991}:12345"
         - "${IMAP_PORT:-143}:143"
diff --git a/generate_config.sh b/generate_config.sh
index 8cde0ffd..7495f057 100755
--- a/generate_config.sh
+++ b/generate_config.sh
@@ -234,6 +234,9 @@ IPV6_NETWORK=fd4d:6169:6c63:6f77::/64
 #API_KEY=
 #API_ALLOW_FROM=127.0.0.1,1.2.3.4
 
+# mail_home is ~/Maildir
+MAILDIR_SUB=Maildir
+
 EOF
 
 mkdir -p data/assets/ssl
diff --git a/update.sh b/update.sh
index be6ef9d7..d879f593 100755
--- a/update.sh
+++ b/update.sh
@@ -243,6 +243,12 @@ for option in ${CONFIG_ARRAY[@]}; do
       echo '# Disable Solr or if you do not want to store a readable index of your mails in solr-vol-1.' >> mailcow.conf
       echo "SKIP_SOLR=y" >> mailcow.conf
   fi
+  elif [[ ${option} == "MAILDIR_SUB" ]]; then
+    if ! grep -q ${option} mailcow.conf; then
+      echo "Adding new option \"${option}\" to mailcow.conf"
+      echo '# MAILDIR_SUB defines a path in a users virtual home to keep the maildir in. Leave empty for updated setups.' >> mailcow.conf
+      echo "MAILDIR_SUB=" >> mailcow.conf
+  fi
   elif ! grep -q ${option} mailcow.conf; then
     echo "Adding new option \"${option}\" to mailcow.conf"
     echo "${option}=n" >> mailcow.conf

From 4aae72779ae28e8fbc8e5ccfec962e931948cf43 Mon Sep 17 00:00:00 2001
From: andryyy <andre.peters@debinux.de>
Date: Mon, 18 Mar 2019 14:15:02 +0100
Subject: [PATCH 3/5] [Dovecot] Remove auth cache

---
 data/conf/dovecot/dovecot.conf | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/data/conf/dovecot/dovecot.conf b/data/conf/dovecot/dovecot.conf
index b81604a2..efb869c6 100644
--- a/data/conf/dovecot/dovecot.conf
+++ b/data/conf/dovecot/dovecot.conf
@@ -384,9 +384,9 @@ service stats {
   }
 }
 imap_max_line_length = 2 M
-auth_cache_verify_password_with_worker = yes
-auth_cache_negative_ttl = 0
-auth_cache_ttl = 30 s
-auth_cache_size = 2 M
+#auth_cache_verify_password_with_worker = yes
+#auth_cache_negative_ttl = 0
+#auth_cache_ttl = 30 s
+#auth_cache_size = 2 M
 !include_try /usr/local/etc/dovecot/extra.conf
 default_client_limit = 10400

From ca2ac00422a2cba483151860397abfe09b3517dc Mon Sep 17 00:00:00 2001
From: andryyy <andre.peters@debinux.de>
Date: Mon, 18 Mar 2019 19:49:05 +0100
Subject: [PATCH 4/5] [Update] Fix MAILDIR_SUB

---
 update.sh | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/update.sh b/update.sh
index d879f593..02c6e8b3 100755
--- a/update.sh
+++ b/update.sh
@@ -135,6 +135,7 @@ CONFIG_ARRAY=(
   "API_KEY"
   "API_ALLOW_FROM"
   "MAILDIR_GC_TIME"
+  "MAILDIR_SUB"
   "ACL_ANYONE"
   "SOLR_HEAP"
   "SKIP_SOLR"
@@ -247,6 +248,7 @@ for option in ${CONFIG_ARRAY[@]}; do
     if ! grep -q ${option} mailcow.conf; then
       echo "Adding new option \"${option}\" to mailcow.conf"
       echo '# MAILDIR_SUB defines a path in a users virtual home to keep the maildir in. Leave empty for updated setups.' >> mailcow.conf
+      echo "#MAILDIR_SUB=Maildir" >> mailcow.conf
       echo "MAILDIR_SUB=" >> mailcow.conf
   fi
   elif ! grep -q ${option} mailcow.conf; then

From 6a13609bf0e1bc75c907bdc46a4099b92de69eb3 Mon Sep 17 00:00:00 2001
From: andryyy <andre.peters@debinux.de>
Date: Tue, 19 Mar 2019 08:45:08 +0100
Subject: [PATCH 5/5] [Web] Fix slow UI by switching QR provider and only
 generating qr image on demand

---
 data/web/inc/ajax/qr_gen.php       | 13 +++++++++++++
 data/web/inc/footer.inc.php        |  9 +++++++++
 data/web/inc/prerequisites.inc.php |  3 ++-
 data/web/modals/footer.php         |  2 +-
 4 files changed, 25 insertions(+), 2 deletions(-)
 create mode 100644 data/web/inc/ajax/qr_gen.php

diff --git a/data/web/inc/ajax/qr_gen.php b/data/web/inc/ajax/qr_gen.php
new file mode 100644
index 00000000..1c543ebe
--- /dev/null
+++ b/data/web/inc/ajax/qr_gen.php
@@ -0,0 +1,13 @@
+<?php
+session_start();
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
+header('Content-Type: text/plain');
+if (!isset($_SESSION['mailcow_cc_role'])) {
+	exit();
+}
+
+if (isset($_GET['token']) && ctype_alnum($_GET['token'])) {
+  echo $tfa->getQRCodeImageAsDataUri($_SESSION['mailcow_cc_username'], $totp_secret);
+}
+
+?>
diff --git a/data/web/inc/footer.inc.php b/data/web/inc/footer.inc.php
index 365cf7da..b8229e26 100644
--- a/data/web/inc/footer.inc.php
+++ b/data/web/inc/footer.inc.php
@@ -93,6 +93,15 @@ $(document).ready(function() {
     }
     if ($(this).val() == "totp") {
       $('#TOTPModal').modal('show');
+      request_token = $('#tfa-qr-img').data('totp-secret');
+      $.ajax({
+        url: '/inc/ajax/qr_gen.php',
+        data: {
+          token: request_token,
+        },
+      }).done(function (result) {
+        $("#tfa-qr-img").attr("src", result);
+      });
       $("option:selected").prop("selected", false);
     }
     if ($(this).val() == "u2f") {
diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php
index 66db8662..7c651803 100644
--- a/data/web/inc/prerequisites.inc.php
+++ b/data/web/inc/prerequisites.inc.php
@@ -36,7 +36,8 @@ foreach ($css_dir as $css_file) {
 
 // U2F API + T/HOTP API
 $u2f = new u2flib_server\U2F('https://' . $_SERVER['HTTP_HOST']);
-$tfa = new RobThree\Auth\TwoFactorAuth($OTP_LABEL);
+$qrprovider = new RobThree\Auth\Providers\Qr\QRServerProvider();
+$tfa = new RobThree\Auth\TwoFactorAuth($OTP_LABEL, 6, 30, 'sha1', $qrprovider);
 
 // Redis
 $redis = new Redis();
diff --git a/data/web/modals/footer.php b/data/web/modals/footer.php
index b5e49b15..b7ebaf08 100644
--- a/data/web/modals/footer.php
+++ b/data/web/modals/footer.php
@@ -81,7 +81,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
           <ol>
             <li>
               <p><?=$lang['tfa']['scan_qr_code'];?></p>
-              <img src="<?=$tfa->getQRCodeImageAsDataUri($_SESSION['mailcow_cc_username'], $totp_secret);?>">
+              <img id="tfa-qr-img" data-totp-secret="<?=$totp_secret;?>" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
               <p class="help-block"><?=$lang['tfa']['enter_qr_code'];?>:<br />
               <code><?=$totp_secret;?></code>
               </p>