From 5b4b184778ac04bd90fb2745d6d5a19f8423d7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 23 Aug 2018 08:49:02 +0200 Subject: [PATCH 01/56] [Web] Fixes to mailcow logo (stickers are coming!) [Web] Fix adding multiple domain aliases, fixes #1705 --- data/web/img/cow_mailcow.svg | 316 ++++++++++++------------- data/web/inc/functions.mailbox.inc.php | 42 ++-- 2 files changed, 174 insertions(+), 184 deletions(-) diff --git a/data/web/img/cow_mailcow.svg b/data/web/img/cow_mailcow.svg index d4577821..6ba98e46 100644 --- a/data/web/img/cow_mailcow.svg +++ b/data/web/img/cow_mailcow.svg @@ -1,5 +1,5 @@ - + image/svg+xml \ No newline at end of file + id="white_1_"> \ No newline at end of file diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index 200ff0ae..b17e204f 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -637,7 +637,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ); 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))); if (!is_valid_domain_name($alias_domain)) { $_SESSION['return'][] = array( @@ -680,30 +680,30 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ); continue; } - } - $stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `active`) - VALUES (:alias_domain, :target_domain, :active)"); - $stmt->execute(array( - ':alias_domain' => $alias_domain, - ':target_domain' => $target_domain, - ':active' => $active - )); - try { - $redis->hSet('DOMAIN_MAP', $alias_domain, 1); - } - catch (RedisException $e) { + $stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `active`) + VALUES (:alias_domain, :target_domain, :active)"); + $stmt->execute(array( + ':alias_domain' => $alias_domain, + ':target_domain' => $target_domain, + ':active' => $active + )); + try { + $redis->hSet('DOMAIN_MAP', $alias_domain, 1); + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) + ); + return false; + } $_SESSION['return'][] = array( - 'type' => 'danger', + 'type' => 'success', 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), - 'msg' => array('redis_error', $e) + 'msg' => array('aliasd_added', htmlspecialchars($alias_domain)) ); - return false; } - $_SESSION['return'][] = array( - 'type' => 'success', - 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), - 'msg' => array('aliasd_added', htmlspecialchars($alias_domain)) - ); break; case 'mailbox': $local_part = strtolower(trim($_data['local_part'])); From 4b09b5b1bb78cb5e5623954bc9680342e982a725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Peters?= Date: Sun, 26 Aug 2018 18:31:44 +0200 Subject: [PATCH 02/56] Update functions.mailbox.inc.php [Web] Remove invalid parameter from sieve_filters update query, fixes #1714 --- data/web/inc/functions.mailbox.inc.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index b17e204f..dd40fa0e 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -139,7 +139,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_name` = 'inactive' WHERE `username` = :username AND `filter_type` = :filter_type"); $stmt->execute(array( ':username' => $username, - 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), ':filter_type' => $filter_type )); } @@ -3394,4 +3393,4 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'mailbox'))) { update_sogo_static_view(); } -} \ No newline at end of file +} From 5e56a46c8434ab4289687a20852678c99b02c429 Mon Sep 17 00:00:00 2001 From: sriccio Date: Tue, 28 Aug 2018 17:14:05 +0200 Subject: [PATCH 03/56] [dovecot] Enhancement to allow to use auth_default_realm When using auth_default_realm in dovecot configuration to setup a default domain name (to allow users to login with only a username instead of the full e-mail address), it breaks the compatibility with imapsync and sogo/sieve vacation. Adding a domain name to dovecot master user/pass fixes this. This never made it do the master branch, so I'm trying a PR again :) See: https://github.com/mailcow/mailcow-dockerized/pull/1331#issuecomment-386534307 --- data/Dockerfiles/dovecot/docker-entrypoint.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index 70ffb701..50e91a12 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -110,8 +110,9 @@ if [[ $(stat -c %U /var/vmail/) != "vmail" ]] ; then chown -R vmail:vmail /var/v # Create random master for SOGo sieve features RAND_USER=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 16 | head -n 1) RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 24 | head -n 1) -echo ${RAND_USER}:$(doveadm pw -s SHA1 -p ${RAND_PASS}) > /usr/local/etc/dovecot/dovecot-master.passwd -echo ${RAND_USER}:${RAND_PASS} > /etc/sogo/sieve.creds + +echo ${RAND_USER}@mailcow.local:$(doveadm pw -s SHA1 -p ${RAND_PASS}) > /usr/local/etc/dovecot/dovecot-master.passwd +echo ${RAND_USER}@mailcow.local:${RAND_PASS} > /etc/sogo/sieve.creds # 401 is user dovecot if [[ ! -f /mail_crypt/ecprivkey.pem || ! -f /mail_crypt/ecpubkey.pem ]]; then From e5b830adeaea28d7c5a79f72b72911cbda0cf668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 31 Aug 2018 23:33:55 +0200 Subject: [PATCH 04/56] [Dovecot] Fix shared namespace --- data/conf/dovecot/dovecot.conf | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/conf/dovecot/dovecot.conf b/data/conf/dovecot/dovecot.conf index dd8db8a3..5fc0024d 100644 --- a/data/conf/dovecot/dovecot.conf +++ b/data/conf/dovecot/dovecot.conf @@ -175,7 +175,7 @@ namespace { type = shared separator = / prefix = Shared/%%u/ - location = maildir:%%h/:CONTROL=~/Shared/%%u:INDEXPVT=~/Shared/%%u + location = maildir:%%h/:INDEX=~/Shared/%%u;CONTROL=~/Shared/%%u subscriptions = no list = children } diff --git a/docker-compose.yml b/docker-compose.yml index 871961a8..c1a3a1c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -136,7 +136,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.34 + image: mailcow/sogo:1.35 build: ./data/Dockerfiles/sogo environment: - DBNAME=${DBNAME} From 8a88514dfde20b277ace76b87a126513e040fade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 7 Sep 2018 16:40:37 +0200 Subject: [PATCH 05/56] [SOGo] Declare /usr/lib/GNUstep/SOGo as volume [Nginx] Mount vols from sogo-mailcow to access /usr/lib/GNUstep/SOGo --- data/Dockerfiles/sogo/Dockerfile | 2 ++ docker-compose.yml | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/data/Dockerfiles/sogo/Dockerfile b/data/Dockerfiles/sogo/Dockerfile index 30a06d24..9d3965a7 100644 --- a/data/Dockerfiles/sogo/Dockerfile +++ b/data/Dockerfiles/sogo/Dockerfile @@ -49,4 +49,6 @@ COPY sogo-full.svg /usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-full.svg COPY acl.diff /acl.diff CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf +VOLUME /usr/lib/GNUstep/SOGo/ + RUN rm -rf /tmp/* /var/tmp/* diff --git a/docker-compose.yml b/docker-compose.yml index c1a3a1c8..353772eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -136,7 +136,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.35 + image: mailcow/sogo:1.36 build: ./data/Dockerfiles/sogo environment: - DBNAME=${DBNAME} @@ -264,6 +264,8 @@ services: - ./data/assets/ssl/:/etc/ssl/mail/:ro - ./data/conf/nginx/:/etc/nginx/conf.d/:rw - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro + volumes_from: + - sogo-mailcow ports: - "${HTTPS_BIND:-0.0.0.0}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}" - "${HTTP_BIND:-0.0.0.0}:${HTTP_PORT:-80}:${HTTP_PORT:-80}" From afc18fd46935e201a9be85ab636f0ed0b77209be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 09:47:47 +0200 Subject: [PATCH 06/56] [Rspamd] Update bad asn, move KEEP_SPAM to a custom lua function --- data/conf/rspamd/custom/bad_asn.map | 15 +++---- data/conf/rspamd/local.d/multimap.conf | 15 ------- data/conf/rspamd/lua/rspamd.local.lua | 54 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/data/conf/rspamd/custom/bad_asn.map b/data/conf/rspamd/custom/bad_asn.map index 8b7a4407..bc9e10f6 100644 --- a/data/conf/rspamd/custom/bad_asn.map +++ b/data/conf/rspamd/custom/bad_asn.map @@ -1,11 +1,10 @@ # High spam networks, disabled by default #201942:5 #Soltia Consulting SL - ipinfo.io -#16276:5 #OVH -#12876:5 #ONLINE S.A.S -#31034:5 -#12874:5 -#30823:5 -#197071:5 +#16276:2 #OVH +#12876:2 #ONLINE S.A.S +#31034:5 #ARUBA-ASN, IT +#12874:5 #FASTWEB, IT +#30823:3 #PKV spam #42831:5 #UK Dedicated Servers Ltd #29119:5 #Aire Networks del Mediterraneo S.L.U. #13335:5 #Cloudflare @@ -17,7 +16,7 @@ #14061:4 #Digitalocean #55293:4 #A2 Hosting #63018:4 #US Dedicated -#197518:2 +#197518:2 #RACKMARKT #44493:2 #46606:2 #49505:2 @@ -25,3 +24,5 @@ #197695:2 #198068:2 #43146:2 +#49100:4 +#39364:4 diff --git a/data/conf/rspamd/local.d/multimap.conf b/data/conf/rspamd/local.d/multimap.conf index da4afaf2..c27a9d63 100644 --- a/data/conf/rspamd/local.d/multimap.conf +++ b/data/conf/rspamd/local.d/multimap.conf @@ -25,13 +25,6 @@ WHITELISTED_FWD_HOST { symbols_set = ["WHITELISTED_FWD_HOST"]; } -KEEP_SPAM { - type = "ip"; - map = "redis://KEEP_SPAM"; - action = "accept"; - symbols_set = ["KEEP_SPAM"]; -} - LOCAL_BL_ASN { require_symbols = "!MAILCOW_WHITE"; type = "asn"; @@ -40,11 +33,3 @@ LOCAL_BL_ASN { description = "Sender's ASN is on the local blacklist"; symbols_set = ["LOCAL_BL_ASN"]; } - -#SPOOFED_SENDER { -# type = "rcpt"; -# filter = "email:domain:tld"; -# map = "redis://DOMAIN_MAP"; -# require_symbols = "AUTH_NA | !RCVD_VIA_SMTP_AUTH"; -# symbols_set = ["SPOOFED_SENDER"]; -#} diff --git a/data/conf/rspamd/lua/rspamd.local.lua b/data/conf/rspamd/lua/rspamd.local.lua index 7c9efbb4..92d223b1 100644 --- a/data/conf/rspamd/lua/rspamd.local.lua +++ b/data/conf/rspamd/lua/rspamd.local.lua @@ -7,6 +7,60 @@ rspamd_config.MAILCOW_AUTH = { end } +rspamd_config:register_symbol({ + name = 'KEEP_SPAM', + type = 'prefilter', + callback = function(task) + local util = require("rspamd_util") + local rspamd_logger = require "rspamd_logger" + local rspamd_ip = require 'rspamd_ip' + local uname = task:get_user() + if uname then + return false + end + local redis_params = rspamd_parse_redis_server('keep_spam') + local ip = task:get_from_ip() + local from_ip_string = ip:to_string() + ip_check_table = {from_ip_string} + local maxbits = 128 + local minbits = 32 + if ip:get_version() == 4 then + maxbits = 32 + minbits = 8 + end + for i=maxbits,minbits,-1 do + local nip = ip:apply_mask(i):to_string() .. "/" .. i + table.insert(ip_check_table, nip) + end + local function keep_spam_cb(err, data) + if err then + rspamd_logger.infox(rspamd_config, "keep_spam query request for ip %s returned invalid or empty data (\"%s\") or error (\"%s\")", ip, data, err) + return false + else + for k,v in pairs(data) do + if (v and v ~= userdata and v == '1') then + rspamd_logger.infox(rspamd_config, "found ip in keep_spam map, setting pre-result", v) + task:set_pre_result('accept', 'IP matched with forward hosts') + end + end + end + end + table.insert(ip_check_table, 1, 'KEEP_SPAM') + local redis_ret_user = rspamd_redis_make_request(task, + redis_params, -- connect params + 'KEEP_SPAM', -- hash key + false, -- is write + keep_spam_cb, --callback + 'HMGET', -- command + ip_check_table -- arguments + ) + if not redis_ret_user then + rspamd_logger.infox(rspamd_config, "cannot check keep_spam redis map") + end + end, + priority = 19 +}) + rspamd_config:register_symbol({ name = 'TAG_MOO', type = 'postfilter', From ad902f0ad8ab781d08583f4c69d6c70570531671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 09:48:11 +0200 Subject: [PATCH 07/56] [SOGo] Remove HTTP server on port 9192 --- data/Dockerfiles/sogo/supervisord.conf | 7 ------- 1 file changed, 7 deletions(-) diff --git a/data/Dockerfiles/sogo/supervisord.conf b/data/Dockerfiles/sogo/supervisord.conf index 2a889560..1c1422b3 100644 --- a/data/Dockerfiles/sogo/supervisord.conf +++ b/data/Dockerfiles/sogo/supervisord.conf @@ -16,13 +16,6 @@ command=/usr/sbin/cron -f autorestart=true priority=2 -[program:sogo-webres] -command=/usr/bin/python -u -m SimpleHTTPServer 9192 -directory=/usr/lib/GNUstep/SOGo/ -user=sogo -autorestart=true -priority=4 - [program:bootstrap-sogo] command=/bootstrap-sogo.sh stdout_logfile=/dev/stdout From ea4a26eabfbb19c04a2bcdcb3e510147ab5c65c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 09:51:37 +0200 Subject: [PATCH 08/56] [Nginx] Use SOGo web resources from local mount --- data/conf/nginx/site.conf | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/data/conf/nginx/site.conf b/data/conf/nginx/site.conf index d25d3b61..9ea4c385 100644 --- a/data/conf/nginx/site.conf +++ b/data/conf/nginx/site.conf @@ -156,44 +156,19 @@ server { } location /SOGo.woa/WebServerResources/ { - proxy_pass http://sogo:9192/WebServerResources/; - proxy_set_header Host $http_host; - proxy_cache sogo; - proxy_cache_valid 200 1d; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - #alias /usr/lib/GNUstep/SOGo/WebServerResources/; - expires $expires; - allow all; + alias /usr/lib/GNUstep/SOGo/WebServerResources/; } location /.woa/WebServerResources/ { - proxy_pass http://sogo:9192/WebServerResources/; - proxy_set_header Host $http_host; - proxy_cache sogo; - proxy_cache_valid 200 1d; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - #alias /usr/lib/GNUstep/SOGo/WebServerResources/; - expires $expires; - allow all; + alias /usr/lib/GNUstep/SOGo/WebServerResources/; } location /SOGo/WebServerResources/ { - proxy_pass http://sogo:9192/WebServerResources/; - proxy_set_header Host $http_host; - proxy_cache sogo; - proxy_cache_valid 200 1d; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - #alias /usr/lib/GNUstep/SOGo/WebServerResources/; - allow all; + alias /usr/lib/GNUstep/SOGo/WebServerResources/; } location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$) { - proxy_pass http://sogo:9192/$1.SOGo/Resources/$2; - proxy_set_header Host $http_host; - proxy_cache sogo; - proxy_cache_valid 200 1d; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - #alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2; + alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2; } include /etc/nginx/conf.d/site.*.custom; From c9554ca02291e64e56a786217de8d4b34b25544d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 21:17:59 +0200 Subject: [PATCH 09/56] [Compose] Update watchdog image [Watchdog] Fix IP detection with multiple networks [Web] Show API field (no docs, no support, wip) [Web] haveibeenpwned.com implementation [Web] User and domain admin ACL (no docs, no support, wip) [Web] Some minor fixes --- data/Dockerfiles/watchdog/watchdog.sh | 27 ++- data/web/admin.php | 15 +- data/web/css/admin.css | 6 - data/web/css/mailbox.css | 3 - data/web/css/mailcow.css | 10 + data/web/edit.php | 68 +++++- data/web/inc/footer.inc.php | 117 ++-------- data/web/inc/functions.acl.inc.php | 216 ++++++++++++++++++ .../inc/functions.address_rewriting.inc.php | 32 +++ data/web/inc/functions.domain_admin.inc.php | 208 ++++++----------- data/web/inc/functions.inc.php | 50 +--- data/web/inc/functions.mailbox.inc.php | 17 +- data/web/inc/functions.policy.inc.php | 32 +-- data/web/inc/functions.ratelimit.inc.php | 8 + data/web/inc/init_db.inc.php | 34 ++- data/web/inc/prerequisites.inc.php | 3 +- data/web/inc/triggers.inc.php | 2 +- data/web/js/admin.js | 4 + data/web/js/api.js | 4 +- data/web/js/edit.js | 12 +- data/web/js/mailbox.js | 19 +- data/web/js/mailcow.js | 193 ++++++++++++++++ data/web/js/sha1.min.js | 1 + data/web/json_api.php | 6 + data/web/lang/lang.de.php | 23 +- data/web/lang/lang.en.php | 21 ++ data/web/mailbox.php | 15 +- data/web/modals/admin.php | 4 +- data/web/modals/mailbox.php | 7 +- data/web/modals/user.php | 4 +- data/web/quarantine.php | 2 +- data/web/user.php | 89 ++------ docker-compose.yml | 2 +- 33 files changed, 793 insertions(+), 461 deletions(-) create mode 100644 data/web/inc/functions.acl.inc.php create mode 100644 data/web/js/mailcow.js create mode 100644 data/web/js/sha1.min.js diff --git a/data/Dockerfiles/watchdog/watchdog.sh b/data/Dockerfiles/watchdog/watchdog.sh index c06abbc2..ec3d5aca 100755 --- a/data/Dockerfiles/watchdog/watchdog.sh +++ b/data/Dockerfiles/watchdog/watchdog.sh @@ -59,10 +59,10 @@ function mail_error() { log_msg "Sent notification email to ${1}" } - get_container_ip() { # ${1} is container CONTAINER_ID=() + CONTAINER_IPS=() CONTAINER_IP= LOOP_C=1 until [[ ${CONTAINER_IP} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] || [[ ${LOOP_C} -gt 5 ]]; do @@ -72,15 +72,21 @@ get_container_ip() { # returned id can have multiple elements (if scaled), shuffle for random test CONTAINER_ID=($(printf "%s\n" "${CONTAINER_ID[@]}" | shuf)) if [[ ! -z ${CONTAINER_ID} ]]; then - for matched_container in "${CONTAINER_ID[@]}"; do - CONTAINER_IP=$(curl --silent http://dockerapi:8080/containers/${matched_container}/json | jq -r '.NetworkSettings.Networks[].IPAddress') - # grep will do nothing if one of these vars is empty - [[ -z ${CONTAINER_IP} ]] && continue - [[ -z ${IPV4_NETWORK} ]] && continue - # only return ips that are part of our network - if ! grep -q ${IPV4_NETWORK} <(echo ${CONTAINER_IP}); then - CONTAINER_IP= - fi + for matched_container in "${CONTAINER_ID[@]}"; do + CONTAINER_IPS=($(curl --silent http://dockerapi:8080/containers/${matched_container}/json | jq -r '.NetworkSettings.Networks[].IPAddress')) + for ip_match in "${CONTAINER_IPS[@]}"; do + # grep will do nothing if one of these vars is empty + [[ -z ${ip_match} ]] && continue + [[ -z ${IPV4_NETWORK} ]] && continue + # only return ips that are part of our network + if ! grep -q ${IPV4_NETWORK} <(echo ${ip_match}); then + continue + else + CONTAINER_IP=${ip_match} + break + fi + done + [[ ! -z ${CONTAINER_IP} ]] && break done fi LOOP_C=$((LOOP_C + 1)) @@ -88,7 +94,6 @@ get_container_ip() { [[ ${LOOP_C} -gt 5 ]] && echo 240.0.0.0 || echo ${CONTAINER_IP} } -# Check functions nginx_checks() { err_count=0 diff_c=0 diff --git a/data/web/admin.php b/data/web/admin.php index d2734431..749c96b6 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -29,7 +29,7 @@ $tfa_data = get_tfa();
- +
@@ -44,7 +44,7 @@ $tfa_data = get_tfa();
-
+
:
@@ -76,12 +76,10 @@ $tfa_data = get_tfa();
- - - - diff --git a/data/web/css/admin.css b/data/web/css/admin.css index a53d721c..bc89f1dd 100644 --- a/data/web/css/admin.css +++ b/data/web/css/admin.css @@ -65,12 +65,6 @@ body.modal-open { font-size:9pt; background:transparent; } -.bootstrap-select { - width: auto!important; -} .table-condensed .input-sm { width: 100%!important; } -.full-width-select { - width: 100%!important; -} diff --git a/data/web/css/mailbox.css b/data/web/css/mailbox.css index da2e96e3..488150d3 100644 --- a/data/web/css/mailbox.css +++ b/data/web/css/mailbox.css @@ -5,9 +5,6 @@ table.footable>tbody>tr.footable-empty>td { .pagination a { text-decoration: none !important; } -.panel panel-default { - overflow: visible !important; -} .btn-group { width: max-content; } diff --git a/data/web/css/mailcow.css b/data/web/css/mailcow.css index 374688a1..04d1b874 100644 --- a/data/web/css/mailcow.css +++ b/data/web/css/mailcow.css @@ -148,3 +148,13 @@ nav .glyphicon { color: #5a5a5a; white-space: nowrap; } +.haveibeenpwned { + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.full-width-select { + width: 100%!important; +} \ No newline at end of file diff --git a/data/web/edit.php b/data/web/edit.php index c4903c28..417f2a7c 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -92,7 +92,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- @@ -111,7 +111,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -140,6 +140,30 @@ if (isset($_SESSION['mailcow_cc_role'])) {
+
+
+
+

ACL

+
+
+
+ +
+
+ +
+
+
+
- +

@@ -278,14 +302,14 @@ if (isset($_SESSION['mailcow_cc_role'])) {
-
+
-
+
@@ -300,14 +324,14 @@ if (isset($_SESSION['mailcow_cc_role'])) {
-
+
-
+
@@ -474,7 +498,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -527,6 +551,30 @@ if (isset($_SESSION['mailcow_cc_role'])) {
+
+
+
+

ACL

+
+
+
+ +
+
+ +
+
+
+
- +
@@ -965,7 +1013,7 @@ else { + + diff --git a/data/web/modals/admin.php b/data/web/modals/admin.php index 7e8656e5..8bca0d87 100644 --- a/data/web/modals/admin.php +++ b/data/web/modals/admin.php @@ -67,7 +67,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- ".htmlspecialchars($domain).""; @@ -79,7 +79,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
diff --git a/data/web/modals/mailbox.php b/data/web/modals/mailbox.php index b4a51893..160ab178 100644 --- a/data/web/modals/mailbox.php +++ b/data/web/modals/mailbox.php @@ -23,7 +23,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- ".htmlspecialchars($domain).""; @@ -48,10 +48,9 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
- - (Generate) +
diff --git a/data/web/modals/user.php b/data/web/modals/user.php index 62ccf1b1..5e0849e2 100644 --- a/data/web/modals/user.php +++ b/data/web/modals/user.php @@ -37,7 +37,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -155,7 +155,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
diff --git a/data/web/quarantine.php b/data/web/quarantine.php index 87f565a1..3e193586 100644 --- a/data/web/quarantine.php +++ b/data/web/quarantine.php @@ -18,7 +18,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
-
+
- +
-
+
@@ -299,9 +280,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
- +
@@ -309,7 +288,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
-

- +
-
- +

@@ -354,26 +329,22 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
- +
-
+
-
+
- +

@@ -381,28 +352,22 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
- +
-
+
-
+
- -
- +
@@ -411,11 +376,9 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
- +
-
+
- +
diff --git a/docker-compose.yml b/docker-compose.yml index 353772eb..cd0c69f8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -330,7 +330,7 @@ services: - /lib/modules:/lib/modules:ro watchdog-mailcow: - image: mailcow/watchdog:1.19 + image: mailcow/watchdog:1.21 # Debug #command: /watchdog.sh build: ./data/Dockerfiles/watchdog From 1a5ec7655ec24ec7c2093e09c858a20440a06835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 21:52:35 +0200 Subject: [PATCH 10/56] [Compose] Update watchdog image --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index cd0c69f8..b8cdbeea 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -330,7 +330,7 @@ services: - /lib/modules:/lib/modules:ro watchdog-mailcow: - image: mailcow/watchdog:1.21 + image: mailcow/watchdog:1.22 # Debug #command: /watchdog.sh build: ./data/Dockerfiles/watchdog From 29aeb5b85d52eb39805dbaf70c1e475b73dbd679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 21:52:48 +0200 Subject: [PATCH 11/56] [Watchdog] Fix SOGo check, fixes #1750 --- data/Dockerfiles/watchdog/watchdog.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/data/Dockerfiles/watchdog/watchdog.sh b/data/Dockerfiles/watchdog/watchdog.sh index ec3d5aca..64795ad3 100755 --- a/data/Dockerfiles/watchdog/watchdog.sh +++ b/data/Dockerfiles/watchdog/watchdog.sh @@ -143,7 +143,6 @@ sogo_checks() { while [ ${err_count} -lt ${THRESHOLD} ]; do host_ip=$(get_container_ip sogo-mailcow) err_c_cur=${err_count} - /usr/lib/nagios/plugins/check_http -4 -H ${host_ip} -u /WebServerResources/css/theme-default.css -p 9192 -R md-default-theme 1>&2; err_count=$(( ${err_count} + $? )) /usr/lib/nagios/plugins/check_http -4 -H ${host_ip} -u /SOGo.index/ -p 20000 -R "SOGo\.MainUI" 1>&2; err_count=$(( ${err_count} + $? )) [ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1 [ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} )) From ce604232e26fdca6a39b00e69b717255c97d4852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 10 Sep 2018 10:56:32 +0200 Subject: [PATCH 12/56] [Web] Add missing data-acl for sync jobs --- data/web/mailbox.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/web/mailbox.php b/data/web/mailbox.php index 32880837..7e865fbb 100644 --- a/data/web/mailbox.php +++ b/data/web/mailbox.php @@ -184,7 +184,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
-
+
- +
@@ -403,10 +403,10 @@ $tfa_data = get_tfa();
@@ -415,7 +415,7 @@ $tfa_data = get_tfa();
- +
- +
@@ -438,41 +438,41 @@ $tfa_data = get_tfa();
- +
- +
- +
/ - +
/ - +

- +
- +
- +
@@ -490,9 +490,9 @@ $tfa_data = get_tfa(); - [] - [whitelist] - [blacklist] + [] + [whitelist] + [blacklist] @@ -527,10 +527,10 @@ $tfa_data = get_tfa();
@@ -539,17 +539,17 @@ $tfa_data = get_tfa();
- +
- +
- +
- +
@@ -564,19 +564,19 @@ $tfa_data = get_tfa();
- +
- +

- @@ -586,7 +586,7 @@ $tfa_data = get_tfa(); ?>
- +
@@ -648,19 +648,19 @@ $tfa_data = get_tfa();
- +
- +
- - + +

- +

@@ -754,21 +754,21 @@ $tfa_data = get_tfa();
- +
- +
- +
- +
diff --git a/data/web/autodiscover.php b/data/web/autodiscover.php index f5bcbf8f..9a167af7 100644 --- a/data/web/autodiscover.php +++ b/data/web/autodiscover.php @@ -27,7 +27,8 @@ if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { } } -$dsn = $database_type . ":host=" . $database_host . ";dbname=" . $database_name; +//$dsn = $database_type . ":host=" . $database_host . ";dbname=" . $database_name; +$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name; $opt = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, diff --git a/data/web/edit.php b/data/web/edit.php index 417f2a7c..a2eb4fb7 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -39,13 +39,13 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
- +
- +
@@ -58,7 +58,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -92,7 +92,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- @@ -111,13 +111,13 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
- +
@@ -136,7 +136,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -159,7 +159,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -189,7 +189,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
- +
- +
- +
- +
- @@ -257,7 +257,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -280,17 +280,17 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
-
- +

@@ -304,15 +304,15 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
- + - +
@@ -326,15 +326,15 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
- + - +
@@ -362,7 +362,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -374,7 +374,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -382,17 +382,17 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
-
- +
- +
@@ -438,13 +438,13 @@ if (isset($_SESSION['mailcow_cc_role'])) {
max. MiB
- +
-
- +
- +
@@ -524,7 +524,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -536,17 +536,17 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
-
- +
@@ -570,7 +570,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -589,19 +589,19 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
- +
- +
@@ -613,7 +613,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -636,13 +636,13 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
- @@ -652,7 +652,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- @@ -673,7 +673,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -719,7 +719,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -766,7 +766,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -933,7 +933,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -984,7 +984,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
diff --git a/data/web/inc/footer.inc.php b/data/web/inc/footer.inc.php index 14d2acf2..9e8daf7b 100644 --- a/data/web/inc/footer.inc.php +++ b/data/web/inc/footer.inc.php @@ -59,7 +59,7 @@ $(document).ready(function() { }); $('#u2f_status_auth').html('

Initializing, please wait...

'); $('#ConfirmTFAModal').on('shown.bs.modal', function(){ - $(this).find('#token').focus(); + $(this).find('input[name=token]').focus(); // If U2F if(document.getElementById("u2f_auth_data") !== null) { $.ajax({ @@ -146,7 +146,7 @@ $(document).ready(function() { }); // CSRF - $('').attr('id', 'csrf_token').attr('name', 'csrf_token').appendTo('form'); + $('').attr('name', 'csrf_token').appendTo('form'); if (sessionStorage.scrollTop != "undefined") { $(window).scrollTop(sessionStorage.scrollTop); } diff --git a/data/web/inc/functions.docker.inc.php b/data/web/inc/functions.docker.inc.php index dbd26375..9c63eec7 100644 --- a/data/web/inc/functions.docker.inc.php +++ b/data/web/inc/functions.docker.inc.php @@ -2,10 +2,13 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) { global $DOCKER_TIMEOUT; $curl = curl_init(); - curl_setopt($curl, CURLOPT_HTTPHEADER,array( 'Content-Type: application/json' )); + curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' )); + // We are using our mail certificates for dockerapi, the names will not match, the certs are trusted anyway + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); switch($action) { case 'get_id': - curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/json'); + curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json'); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); @@ -38,7 +41,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex } return false; case 'containers': - curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/json'); + curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json'); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); @@ -74,7 +77,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex break; case 'info': if (empty($service_name)) { - curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/json'); + curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json'); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_POST, 0); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); @@ -82,7 +85,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex else { $container_id = docker('get_id', $service_name); if (ctype_xdigit($container_id)) { - curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/json'); + curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/' . $container_id . '/json'); } else { // logger(array('return' => array( @@ -144,7 +147,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex if (!empty($attr1)) { $container_id = docker('get_id', $service_name); if (ctype_xdigit($container_id) && ctype_alnum($attr1)) { - curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/' . $attr1); + curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/' . $container_id . '/' . $attr1); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT); if (!empty($attr2)) { @@ -158,19 +161,19 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex if ($response === false) { $err = curl_error($curl); curl_close($curl); - logger(array('return' => array(array( - 'type' => 'danger', - 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), - 'msg' => $err, - )))); + // logger(array('return' => array(array( + // 'type' => 'danger', + // 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + // 'msg' => $err, + // )))); return $err; } else { curl_close($curl); - logger(array('return' => array(array( - 'type' => 'success', - 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), - )))); + // logger(array('return' => array(array( + // 'type' => 'success', + // 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + // )))); if (empty($response)) { return true; } diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 94eada4f..f915d5d0 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -18,6 +18,17 @@ function last_login($user) { return false; } } +function flush_memcached() { + try { + $m = new Memcached(); + $m->addServer('memcached', 11211); + $m->flush(); + } + catch ( Exception $e ) { + // Dunno + } +} + function logger($_data = false) { /* logger() will be called as last function @@ -510,6 +521,7 @@ function update_sogo_static_view() { $stmt = $pdo->query("REPLACE INTO _sogo_static_view SELECT * from sogo_view"); $stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');"); } + flush_memcached(); } function edit_user_account($_data) { global $lang; diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index 8393c5f6..e06ac397 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -2776,6 +2776,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { `mailbox`.`active` AS `active_int`, CASE `mailbox`.`active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`, `mailbox`.`domain`, + `mailbox`.`maildir`, `mailbox`.`quota`, `quota2`.`bytes`, `attributes`, @@ -2806,6 +2807,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $mailboxdata['active'] = $row['active']; $mailboxdata['active_int'] = $row['active_int']; $mailboxdata['domain'] = $row['domain']; + $mailboxdata['maildir'] = $row['maildir']; $mailboxdata['quota'] = $row['quota']; $mailboxdata['attributes'] = json_decode($row['attributes'], true); $mailboxdata['quota_used'] = intval($row['bytes']); @@ -3054,6 +3056,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ); continue; } + $exec_fields = array('cmd' => 'maildir_cleanup', 'maildir' => $domain); + $maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true); + if ($maildir_gc['type'] != 'success') { + $_SESSION['return'][] = array( + 'type' => 'warning', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'Could not move maildir to garbage collector: ' . $maildir_gc['msg'] + ); + } + return false; $stmt = $pdo->prepare("DELETE FROM `domain` WHERE `domain` = :domain"); $stmt->execute(array( ':domain' => $domain, @@ -3078,17 +3090,17 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $stmt->execute(array( ':domain' => '%@'.$domain, )); - $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` = :domain"); + $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` LIKE :domain"); $stmt->execute(array( ':domain' => '%@'.$domain, )); - $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` = :domain"); + $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` LIKE :domain"); $stmt->execute(array( ':domain' => '%@'.$domain, )); $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :domain"); $stmt->execute(array( - ':domain' => '%@'.$domain, + ':domain' => $domain, )); $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :domain"); $stmt->execute(array( @@ -3227,6 +3239,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ); continue; } + $maildir = mailbox('get', 'mailbox_details', $username)['maildir']; + $exec_fields = array('cmd' => 'maildir_cleanup', 'maildir' => $maildir); + $maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true); + if ($maildir_gc['type'] != 'success') { + $_SESSION['return'][] = array( + 'type' => 'warning', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'Could not move maildir to garbage collector: ' . $maildir_gc['msg'] + ); + } $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `goto` = :username"); $stmt->execute(array( ':username' => $username diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index 58566ab7..571713be 100644 --- a/data/web/inc/init_db.inc.php +++ b/data/web/inc/init_db.inc.php @@ -3,7 +3,7 @@ function init_db_schema() { try { global $pdo; - $db_version = "01092018_1902"; + $db_version = "21092018_1902"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php index aedda083..209c7184 100644 --- a/data/web/inc/prerequisites.inc.php +++ b/data/web/inc/prerequisites.inc.php @@ -35,7 +35,7 @@ $hrs = floor($mins / 60); $mins -= $hrs * 60; $offset = sprintf('%+d:%02d', $hrs*$sgn, $mins); -$dsn = $database_type . ":host=" . $database_host . ";dbname=" . $database_name; +$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name; $opt = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, @@ -46,11 +46,20 @@ try { $pdo = new PDO($dsn, $database_user, $database_pass, $opt); } catch (PDOException $e) { +// Stop when SQL connection fails ?> -
Connection to database failed.

The following error was reported:
getMessage();?>
+
Connection to database failed.

The following error was reported:
getMessage();?>
+
Connection to dockerapi container failed.

The following error was reported:
-
+' + ' Test' + ' ' + lang.edit + '' + - ' ' + lang.remove + '' + + ' ' + lang.remove + '' + ''; item.chkbox = ''; }); } else if (table == 'forwardinghoststable') { $.each(data, function (i, item) { item.action = ''; if (item.keep_spam == "yes") { item.keep_spam = lang.no; @@ -145,7 +145,7 @@ jQuery(function($){ item.chkbox = ''; item.action = ''; }); diff --git a/data/web/js/api.js b/data/web/js/api.js index a573d7f4..e8293dbc 100644 --- a/data/web/js/api.js +++ b/data/web/js/api.js @@ -71,7 +71,7 @@ $(document).ready(function() { }); // General API edit actions - $(document).on('click', '#edit_selected', function(e) { + $(document).on('click', "[data-action='edit_selected']", function(e) { e.preventDefault(); var id = $(this).data('id'); var api_url = $(this).data('api-url'); @@ -159,7 +159,7 @@ $(document).ready(function() { }); // General API add actions - $(document).on('click', '#add_item', function(e) { + $(document).on('click', "[data-action='add_item']", function(e) { e.preventDefault(); var id = $(this).data('id'); var api_url = $(this).data('api-url'); @@ -252,7 +252,7 @@ $(document).ready(function() { }); // General API delete actions - $(document).on('click', '#delete_selected', function(e) { + $(document).on('click', "[data-action='delete_selected']", function(e) { e.preventDefault(); var id = $(this).data('id'); // If clicked element #delete_selected has data-item attribute, it is added to "items" @@ -283,6 +283,7 @@ $(document).ready(function() { keyboard: false }) .one('click', '#IsConfirmed', function(e) { + if (is_active($('#IsConfirmed'))) { return false; } $.ajax({ type: "POST", dataType: "json", diff --git a/data/web/js/edit.js b/data/web/js/edit.js index f91f6b70..45690710 100644 --- a/data/web/js/edit.js +++ b/data/web/js/edit.js @@ -10,37 +10,43 @@ $(document).ready(function() { }); $("#disable_sender_check").click(function( event ) { if ($("form[data-id='editmailbox'] #disable_sender_check:checked").length > 0) { - $('#sender_acl').prop('disabled', true); - $('#sender_acl').selectpicker('refresh'); + $('#editSelectSenderACL').prop('disabled', true); + $('#editSelectSenderACL').selectpicker('refresh'); } else { - $('#sender_acl').prop('disabled', false); - $('#sender_acl').selectpicker('refresh'); + $('#editSelectSenderACL').prop('disabled', false); + $('#editSelectSenderACL').selectpicker('refresh'); } }); if ($("form[data-id='editalias'] .goto_checkbox:checked").length > 0) { $('#textarea_alias_goto').prop('disabled', true); } + $("#script_data").numberedtextarea({allowTabChar: true}); + + $("#mailbox-password-warning-close").click(function( event ) { + $('#mailbox-passwd-hidden-info').addClass('hidden'); + $('#mailbox-passwd-form-groups').removeClass('hidden'); + }); }); -if ($("#multiple_bookings_select").val() == "custom") { +if ($("#editSelectMultipleBookings").val() == "custom") { $("#multiple_bookings_custom_div").show(); - $("#multiple_bookings").val($("#multiple_bookings_custom").val()); + $('input[name=multiple_bookings]').val($("#multiple_bookings_custom").val()); } -$("#multiple_bookings_select").change(function() { - $("#multiple_bookings").val($("#multiple_bookings_select").val()); - if ($("#multiple_bookings").val() == "custom") { +$("#editSelectMultipleBookings").change(function() { + $('input[name=multiple_bookings]').val($("#editSelectMultipleBookings").val()); + if ($('input[name=multiple_bookings]').val() == "custom") { $("#multiple_bookings_custom_div").show(); } else { $("#multiple_bookings_custom_div").hide(); } }); -if ($("#sender_acl option[value='\*']:selected").length > 0){ +if ($("#editSelectSenderACL option[value='\*']:selected").length > 0){ $("#sender_acl_disabled").show(); } -$('#sender_acl').change(function() { - if ($("#sender_acl option[value='\*']:selected").length > 0){ +$('#editSelectSenderACL').change(function() { + if ($("#editSelectSenderACL option[value='\*']:selected").length > 0){ $("#sender_acl_disabled").show(); } else { @@ -48,7 +54,7 @@ $('#sender_acl').change(function() { } }); $("#multiple_bookings_custom").bind("change keypress keyup blur", function() { - $("#multiple_bookings").val($("#multiple_bookings_custom").val()); + $('input[name=multiple_bookings]').val($("#multiple_bookings_custom").val()); }); jQuery(function($){ // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript diff --git a/data/web/js/mailbox.js b/data/web/js/mailbox.js index 34f3ec20..836ec872 100644 --- a/data/web/js/mailbox.js +++ b/data/web/js/mailbox.js @@ -6,7 +6,6 @@ $(document).ready(function() { var domain_list = []; $.ajax({ dataType: 'json', - 'async': false, url: '/api/v1/get/domain/all', jsonp: false, error: function () { @@ -85,10 +84,10 @@ $(document).ready(function() { event.preventDefault(); $('[data-hibp]').trigger('input'); var random_passwd = Math.random().toString(36).slice(-8) - $('#password').prop('type', 'text'); - $('#password').val(random_passwd); - $('#password2').prop('type', 'text'); - $('#password2').val(random_passwd); + $(this).closest("form").find("input[name='password']").prop('type', 'text'); + $(this).closest("form").find("input[name='password2']").prop('type', 'text'); + $(this).closest("form").find("input[name='password']").val(random_passwd); + $(this).closest("form").find("input[name='password2']").val(random_passwd); }); $(".goto_checkbox").click(function( event ) { @@ -302,7 +301,7 @@ jQuery(function($){ item.action = '
'; if (role == "admin") { item.action += ' ' + lang.edit + '' + - ' ' + lang.remove + ''; + ' ' + lang.remove + ''; } else { item.action += ' ' + lang.edit + ''; @@ -386,14 +385,14 @@ jQuery(function($){ if (acl_data.login_as === 1) { item.action = ''; } else { item.action = ''; } item.in_use = '
' + @@ -461,7 +460,7 @@ jQuery(function($){ } item.action = ''; item.chkbox = ''; item.name = escapeHtml(item.name); @@ -520,7 +519,7 @@ jQuery(function($){ $.each(data, function (i, item) { item.action = ''; item.chkbox = ''; item.local_dest = escapeHtml(item.local_dest); @@ -583,7 +582,7 @@ jQuery(function($){ item.recipient_map_new = escapeHtml(item.recipient_map_new); item.action = ''; item.chkbox = ''; }); @@ -638,7 +637,7 @@ jQuery(function($){ $.each(data, function (i, item) { item.action = ''; item.chkbox = ''; item.goto = escapeHtml(item.goto.replace(/,/g, " ")); @@ -713,7 +712,7 @@ jQuery(function($){ $.each(data, function (i, item) { item.action = '' + '
'; item.chkbox = ''; @@ -781,7 +780,7 @@ jQuery(function($){ item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1; item.action = ''; item.chkbox = ''; if (item.is_running == 1) { @@ -852,7 +851,7 @@ jQuery(function($){ item.filter_type = '
' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '
' item.action = ''; item.chkbox = '' }); diff --git a/data/web/js/mailcow.js b/data/web/js/mailcow.js index d9019c23..89cfabf5 100644 --- a/data/web/js/mailcow.js +++ b/data/web/js/mailcow.js @@ -110,7 +110,7 @@ $(document).ready(function() { // Disable disallowed inputs $('[data-acl="0"]').each(function(){ - if ($(this).attr('class') == 'btn-group') { + if ($(this).hasClass('btn-group')) { $(this).find('a').each(function(){ $(this).removeClass('dropdown-toggle') .removeAttr('data-toggle') @@ -124,7 +124,7 @@ $(document).ready(function() { $(this).find('button').each(function() { $(this).attr("disabled", true); }); - } else if ($(this).attr('class') == 'input-group') { + } else if ($(this).hasClass('input-group')) { $(this).find('input').each(function() { $(this).removeClass('dropdown-toggle') .removeAttr('data-toggle') diff --git a/data/web/js/quarantine.js b/data/web/js/quarantine.js index 21ec9ddc..f8438099 100644 --- a/data/web/js/quarantine.js +++ b/data/web/js/quarantine.js @@ -28,7 +28,7 @@ jQuery(function($){ $.each(data, function (i, item) { item.action = ''; item.chkbox = ''; }); diff --git a/data/web/js/user.js b/data/web/js/user.js index 226d039a..5649d6c6 100644 --- a/data/web/js/user.js +++ b/data/web/js/user.js @@ -64,7 +64,7 @@ jQuery(function($){ $.each(data, function (i, item) { if (acl_data.spam_alias === 1) { item.action = ''; item.chkbox = ''; item.address = escapeHtml(item.address); @@ -123,7 +123,7 @@ jQuery(function($){ if (acl_data.syncjobs === 1) { item.action = ''; item.chkbox = ''; } diff --git a/data/web/mailbox.php b/data/web/mailbox.php index 7e865fbb..70d8dbb6 100644 --- a/data/web/mailbox.php +++ b/data/web/mailbox.php @@ -44,10 +44,10 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; @@ -74,10 +74,10 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
@@ -101,10 +101,10 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; @@ -134,10 +134,10 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; @@ -161,10 +161,10 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; @@ -188,12 +188,12 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; @@ -218,13 +218,13 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; @@ -249,13 +249,13 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; @@ -277,10 +277,10 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; diff --git a/data/web/modals/admin.php b/data/web/modals/admin.php index 8bca0d87..2cce623e 100644 --- a/data/web/modals/admin.php +++ b/data/web/modals/admin.php @@ -17,13 +17,13 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
- +
@@ -35,7 +35,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -60,7 +60,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- + a-z A-Z - _ .
@@ -79,13 +79,13 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
- +
@@ -97,7 +97,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -115,11 +115,11 @@ if (!isset($_SESSION['mailcow_cc_role'])) {