Forráskód Böngészése

[Ejabberd] More fixes for Ejabberd integration (WIP)

andryyy 4 éve
szülő
commit
f2453e316f

+ 4 - 4
data/Dockerfiles/ejabberd/mailcowCommandExecutor.php

@@ -98,16 +98,16 @@ class mailcowCommandExecutor implements CommandExecutorInterface {
             return hash_equals(hash($scheme, $password, true), $hash);
             return hash_equals(hash($scheme, $password, true), $hash);
 
 
           case "SMD5":
           case "SMD5":
-            return verify_salted_hash($hash, $password, 'md5', 16);
+            return self::verify_salted_hash($hash, $password, 'md5', 16);
 
 
           case "SSHA":
           case "SSHA":
-            return verify_salted_hash($hash, $password, 'sha1', 20);
+            return self::verify_salted_hash($hash, $password, 'sha1', 20);
 
 
           case "SSHA256":
           case "SSHA256":
-            return verify_salted_hash($hash, $password, 'sha256', 32);
+            return self::verify_salted_hash($hash, $password, 'sha256', 32);
 
 
           case "SSHA512":
           case "SSHA512":
-            return verify_salted_hash($hash, $password, 'sha512', 64);
+            return self::verify_salted_hash($hash, $password, 'sha512', 64);
 
 
           default:
           default:
             return false;
             return false;

+ 3 - 0
data/Dockerfiles/phpfpm/docker-entrypoint.sh

@@ -172,6 +172,9 @@ fi
 # Fix permissions for global filters
 # Fix permissions for global filters
 chown -R 82:82 /global_sieve/*
 chown -R 82:82 /global_sieve/*
 
 
+[[ ! -f /etc/nginx/conf.d/ejabberd.conf ]] && echo '# Autogenerated by mailcow' > /etc/nginx/conf.d/ejabberd.conf
+chown 82:82 /etc/nginx/conf.d/ejabberd.conf
+
 # Run hooks
 # Run hooks
 for file in /hooks/*; do
 for file in /hooks/*; do
   if [ -x "${file}" ]; then
   if [ -x "${file}" ]; then

+ 3 - 1
data/web/inc/functions.mailbox.inc.php

@@ -443,7 +443,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
           }
           }
           $domain				= idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
           $domain				= idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
           $description  = $_data['description'];
           $description  = $_data['description'];
-          $xmpp_prefix  = $_data['xmpp_prefix'];
+          $xmpp_prefix = preg_replace('/[^\da-z-]/i', '', $_data['xmpp_prefix']);
           if (empty($description)) {
           if (empty($description)) {
             $description = $domain;
             $description = $domain;
           }
           }
@@ -2115,6 +2115,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
                 );
                 );
                 continue;
                 continue;
               }
               }
+              $xmpp_prefix = preg_replace('/[^\da-z-]/i', '', $xmpp_prefix);
               $stmt = $pdo->prepare("UPDATE `domain` SET
               $stmt = $pdo->prepare("UPDATE `domain` SET
               `description` = :description,
               `description` = :description,
               `gal` = :gal,
               `gal` = :gal,
@@ -2167,6 +2168,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
                 );
                 );
                 continue;
                 continue;
               }
               }
+              $xmpp_prefix = preg_replace('/[^\da-z-]/i', '', $xmpp_prefix);
               // todo: should be using api here
               // todo: should be using api here
               $stmt = $pdo->prepare("SELECT
               $stmt = $pdo->prepare("SELECT
                   COUNT(*) AS count,
                   COUNT(*) AS count,

+ 96 - 24
data/web/inc/functions.xmpp.inc.php

@@ -128,55 +128,104 @@ function xmpp_rebuild_configs() {
 
 
     touch('/ejabberd/ejabberd_hosts.yml');
     touch('/ejabberd/ejabberd_hosts.yml');
     touch('/ejabberd/ejabberd_acl.yml');
     touch('/ejabberd/ejabberd_acl.yml');
+    touch('/etc/nginx/conf.d/ejabberd.conf');
     $ejabberd_hosts_md5 = md5_file('/ejabberd/ejabberd_hosts.yml');
     $ejabberd_hosts_md5 = md5_file('/ejabberd/ejabberd_hosts.yml');
     $ejabberd_acl_md5 = md5_file('/ejabberd/ejabberd_acl.yml');
     $ejabberd_acl_md5 = md5_file('/ejabberd/ejabberd_acl.yml');
+    $ejabberd_site_md5 = md5_file('/etc/nginx/conf.d/ejabberd.conf');
 
 
     if (!empty($xmpp_domains)) {
     if (!empty($xmpp_domains)) {
       // Handle hosts file
       // Handle hosts file
-      $map_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
-      if (!$map_handle) {
+      $hosts_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
+      if (!$hosts_handle) {
         throw new Exception($lang['danger']['file_open_error']);
         throw new Exception($lang['danger']['file_open_error']);
       }
       }
-      fwrite($map_handle, '# Autogenerated by mailcow' . PHP_EOL);
-      fwrite($map_handle, 'hosts:' . PHP_EOL);
+      fwrite($hosts_handle, '# Autogenerated by mailcow' . PHP_EOL);
+      fwrite($hosts_handle, 'hosts:' . PHP_EOL);
       foreach ($xmpp_domains as $domain => $domain_values) {
       foreach ($xmpp_domains as $domain => $domain_values) {
-        fwrite($map_handle, '  - ' . $xmpp_domains[$domain]['xmpp_host'] . PHP_EOL);
+        fwrite($hosts_handle, '  - ' . $xmpp_domains[$domain]['xmpp_host'] . PHP_EOL);
       }
       }
-      fclose($map_handle);
+      fclose($hosts_handle);
 
 
       // Handle ACL file
       // Handle ACL file
-      $map_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
-      if (!$map_handle) {
+      $acl_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
+      if (!$acl_handle) {
         throw new Exception($lang['danger']['file_open_error']);
         throw new Exception($lang['danger']['file_open_error']);
       }
       }
-      fwrite($map_handle, '# Autogenerated by mailcow' . PHP_EOL);
-      fwrite($map_handle, 'append_host_config:' . PHP_EOL);
+      fwrite($acl_handle, '# Autogenerated by mailcow' . PHP_EOL);
+      fwrite($acl_handle, 'append_host_config:' . PHP_EOL);
       foreach ($xmpp_domains as $domain => $domain_values) {
       foreach ($xmpp_domains as $domain => $domain_values) {
-        fwrite($map_handle, '  ' . $xmpp_domains[$domain]['xmpp_host'] . ':' . PHP_EOL);
-        fwrite($map_handle, '    acl:' . PHP_EOL);
-        fwrite($map_handle, '      admin:' . PHP_EOL);
-        fwrite($map_handle, '        user:' . PHP_EOL);
+        fwrite($acl_handle, '  ' . $xmpp_domains[$domain]['xmpp_host'] . ':' . PHP_EOL);
+        fwrite($acl_handle, '    acl:' . PHP_EOL);
+        fwrite($acl_handle, '      admin:' . PHP_EOL);
+        fwrite($acl_handle, '        user:' . PHP_EOL);
         foreach ($xmpp_domains[$domain]['xmpp_admins'] as $xmpp_admin) {
         foreach ($xmpp_domains[$domain]['xmpp_admins'] as $xmpp_admin) {
-          fwrite($map_handle, '          - ' . $xmpp_admin . PHP_EOL);
+          fwrite($acl_handle, '          - ' . $xmpp_admin . PHP_EOL);
         }
         }
       }
       }
-      fclose($map_handle);
+      fclose($acl_handle);
+
+      // Handle Nginx site
+      $site_handle = @fopen('/etc/nginx/conf.d/ejabberd.conf', 'r+');
+      if ($site_handle !== false) {
+        ftruncate($site_handle, 0);
+        fclose($site_handle);
+      }
+      $site_handle = fopen('/etc/nginx/conf.d/ejabberd.conf', 'w');
+      if (!$site_handle) {
+        throw new Exception($lang['danger']['file_open_error']);
+      }
+      fwrite($site_handle, '# Autogenerated by mailcow' . PHP_EOL);
+      foreach ($xmpp_domains as $domain => $domain_values) {
+        $site_config = <<<EOF
+server {
+  root /web;
+
+  listen 80;
+  listen [::]:80;
+
+  server_name *.%s %s;
+
+  if (\$request_uri ~* "%%0A|%%0D") {
+    return 403;
+  }
+
+  set_real_ip_from 10.0.0.0/8;
+  set_real_ip_from 172.16.0.0/12;
+  set_real_ip_from 192.168.0.0/16;
+  set_real_ip_from fc00::/7;
+  real_ip_header X-Forwarded-For;
+  real_ip_recursive on;
+
+  location / {
+    proxy_pass http://ejabberd:5281/;
+    proxy_set_header Host \$http_host;
+    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
+    proxy_set_header X-Real-IP \$remote_addr;
+    proxy_redirect off;
+  }
+}
+
+EOF;
+        fwrite($site_handle, sprintf($site_config, $xmpp_domains[$domain]['xmpp_host'], $xmpp_domains[$domain]['xmpp_host']));
+      }
+      fclose($site_handle);
     }
     }
     else {
     else {
       // Write empty hosts file
       // Write empty hosts file
-      $map_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
-      if (!$map_handle) {
+      $hosts_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
+      if (!$hosts_handle) {
         throw new Exception($lang['danger']['file_open_error']);
         throw new Exception($lang['danger']['file_open_error']);
       }
       }
-      fwrite($map_handle, '# Autogenerated by mailcow' . PHP_EOL);
-      fclose($map_handle);
+      fwrite($hosts_handle, '# Autogenerated by mailcow' . PHP_EOL);
+      fclose($hosts_handle);
+
       // Write empty ACL file
       // Write empty ACL file
-      $map_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
-      if (!$map_handle) {
+      $acl_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
+      if (!$acl_handle) {
         throw new Exception($lang['danger']['file_open_error']);
         throw new Exception($lang['danger']['file_open_error']);
       }
       }
-      fwrite($map_handle, '# Autogenerated by mailcow' . PHP_EOL);
-      fclose($map_handle);
+      fwrite($acl_handle, '# Autogenerated by mailcow' . PHP_EOL);
+      fclose($acl_handle);
     }
     }
 
 
     if (md5_file('/ejabberd/ejabberd_acl.yml') != $ejabberd_acl_md5) {
     if (md5_file('/ejabberd/ejabberd_acl.yml') != $ejabberd_acl_md5) {
@@ -196,6 +245,29 @@ function xmpp_rebuild_configs() {
       );
       );
     }
     }
 
 
+    if (md5_file('/etc/nginx/conf.d/ejabberd.conf') != $ejabberd_site_md5) {
+      $response = json_decode(docker('post', 'nginx-mailcow', 'exec', array("cmd" => "reload", "task" => "nginx"), 'Content-type: application/json'), true);
+      if (isset($response['type']) && $response['type'] == "success") {
+        $_SESSION['return'][] = array(
+          'type' => 'success',
+          'log' => array(__FUNCTION__, $_action, $_data_log),
+          'msg' => 'nginx_reloaded'
+        );
+      }
+      else {
+        if (!empty($response['msg'])) {
+          $error = $response['msg'];
+        }
+        else {
+          $error = '-';
+        }
+        $_SESSION['return'][] = array(
+          'type' => 'danger',
+          'log' => array(__FUNCTION__, $_action, $_data_log),
+          'msg' => array('nginx_reload_failed', htmlspecialchars($error))
+        );
+      }
+    }
   }
   }
   catch (Exception $e) {
   catch (Exception $e) {
     $_SESSION['return'][] = array(
     $_SESSION['return'][] = array(

+ 2 - 0
data/web/lang/lang.de.json

@@ -396,6 +396,7 @@
         "max_quota_in_use": "Mailbox-Speicherplatzlimit muss größer oder gleich %d MiB sein",
         "max_quota_in_use": "Mailbox-Speicherplatzlimit muss größer oder gleich %d MiB sein",
         "maxquota_empty": "Max. Speicherplatz pro Mailbox darf nicht 0 sein.",
         "maxquota_empty": "Max. Speicherplatz pro Mailbox darf nicht 0 sein.",
         "mysql_error": "MySQL-Fehler: %s",
         "mysql_error": "MySQL-Fehler: %s",
+        "nginx_reload_failed": "Nginx Reload ist fehlgeschlagen: %s",
         "network_host_invalid": "Netzwerk oder Host ungültig: %s",
         "network_host_invalid": "Netzwerk oder Host ungültig: %s",
         "next_hop_interferes": "%s verhindert das Hinzufügen von Next Hop %s",
         "next_hop_interferes": "%s verhindert das Hinzufügen von Next Hop %s",
         "next_hop_interferes_any": "Ein vorhandener Eintrag verhindert das Hinzufügen von Next Hop %s",
         "next_hop_interferes_any": "Ein vorhandener Eintrag verhindert das Hinzufügen von Next Hop %s",
@@ -893,6 +894,7 @@
         "mailbox_added": "Mailbox %s wurde angelegt",
         "mailbox_added": "Mailbox %s wurde angelegt",
         "mailbox_modified": "Änderungen an Mailbox %s wurden gespeichert",
         "mailbox_modified": "Änderungen an Mailbox %s wurden gespeichert",
         "mailbox_removed": "Mailbox %s wurde entfernt",
         "mailbox_removed": "Mailbox %s wurde entfernt",
+        "nginx_reloaded": "Nginx wurde neu geladen",
         "object_modified": "Änderungen an Objekt %s wurden gespeichert",
         "object_modified": "Änderungen an Objekt %s wurden gespeichert",
         "pushover_settings_edited": "Pushover Konfiguration gespeichert, bitte den Zugang im Anschluss verifizieren.",
         "pushover_settings_edited": "Pushover Konfiguration gespeichert, bitte den Zugang im Anschluss verifizieren.",
         "qlearn_spam": "Nachricht ID %s wurde als Spam gelernt und gelöscht",
         "qlearn_spam": "Nachricht ID %s wurde als Spam gelernt und gelöscht",

+ 2 - 0
data/web/lang/lang.en.json

@@ -397,6 +397,7 @@
         "max_quota_in_use": "Mailbox quota must be greater or equal to %d MiB",
         "max_quota_in_use": "Mailbox quota must be greater or equal to %d MiB",
         "maxquota_empty": "Max. quota per mailbox must not be 0.",
         "maxquota_empty": "Max. quota per mailbox must not be 0.",
         "mysql_error": "MySQL error: %s",
         "mysql_error": "MySQL error: %s",
+        "nginx_reload_failed": "Nginx reload failed: %s",
         "network_host_invalid": "Invalid network or host: %s",
         "network_host_invalid": "Invalid network or host: %s",
         "next_hop_interferes": "%s interferes with nexthop %s",
         "next_hop_interferes": "%s interferes with nexthop %s",
         "next_hop_interferes_any": "An existing next hop interferes with %s",
         "next_hop_interferes_any": "An existing next hop interferes with %s",
@@ -894,6 +895,7 @@
         "mailbox_added": "Mailbox %s has been added",
         "mailbox_added": "Mailbox %s has been added",
         "mailbox_modified": "Changes to mailbox %s have been saved",
         "mailbox_modified": "Changes to mailbox %s have been saved",
         "mailbox_removed": "Mailbox %s has been removed",
         "mailbox_removed": "Mailbox %s has been removed",
+        "nginx_reloaded": "Nginx was reloaded",
         "object_modified": "Changes to object %s have been saved",
         "object_modified": "Changes to object %s have been saved",
         "pushover_settings_edited": "Pushover settings successfully set, please verify credentials.",
         "pushover_settings_edited": "Pushover settings successfully set, please verify credentials.",
         "qlearn_spam": "Message ID %s was learned as spam and deleted",
         "qlearn_spam": "Message ID %s was learned as spam and deleted",

+ 8 - 6
docker-compose.yml

@@ -101,13 +101,13 @@ services:
             - rspamd
             - rspamd
 
 
     php-fpm-mailcow:
     php-fpm-mailcow:
-      image: mailcow/phpfpm:1.70
+      image: mailcow/phpfpm:1.71
       command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
       command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
       depends_on:
       depends_on:
         - redis-mailcow
         - redis-mailcow
       volumes:
       volumes:
         - ./data/hooks/phpfpm:/hooks:Z
         - ./data/hooks/phpfpm:/hooks:Z
-        - ./data/web:/web:rw,z
+        - ./data/web:/web:z
         - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z
         - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z
         - ./data/conf/rspamd/custom/:/rspamd_custom_maps:z
         - ./data/conf/rspamd/custom/:/rspamd_custom_maps:z
         - rspamd-vol-1:/var/lib/rspamd:z
         - rspamd-vol-1:/var/lib/rspamd:z
@@ -123,6 +123,7 @@ services:
         - ./data/conf/dovecot/global_sieve_after:/global_sieve/after:z
         - ./data/conf/dovecot/global_sieve_after:/global_sieve/after:z
         - ./data/assets/templates:/tpls:z
         - ./data/assets/templates:/tpls:z
         - ./data/conf/ejabberd/autogen:/ejabberd/:z
         - ./data/conf/ejabberd/autogen:/ejabberd/:z
+        - ./data/conf/nginx/:/etc/nginx/conf.d/:z
       dns:
       dns:
         - ${IPV4_NETWORK:-172.22.1}.254
         - ${IPV4_NETWORK:-172.22.1}.254
       environment:
       environment:
@@ -324,6 +325,7 @@ services:
         until ping sogo -c1 > /dev/null; do sleep 1; done &&
         until ping sogo -c1 > /dev/null; do sleep 1; done &&
         until ping redis -c1 > /dev/null; do sleep 1; done &&
         until ping redis -c1 > /dev/null; do sleep 1; done &&
         until ping rspamd -c1 > /dev/null; do sleep 1; done &&
         until ping rspamd -c1 > /dev/null; do sleep 1; done &&
+        until ping ejabberd -c1 > /dev/null; do sleep 1; done &&
         exec nginx -g 'daemon off;'"
         exec nginx -g 'daemon off;'"
       environment:
       environment:
         - HTTPS_PORT=${HTTPS_PORT:-443}
         - HTTPS_PORT=${HTTPS_PORT:-443}
@@ -337,7 +339,7 @@ services:
         - ./data/web:/web:ro,z
         - ./data/web:/web:ro,z
         - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z
         - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z
         - ./data/assets/ssl/:/etc/ssl/mail/:ro,z
         - ./data/assets/ssl/:/etc/ssl/mail/:ro,z
-        - ./data/conf/nginx/:/etc/nginx/conf.d/:rw,Z
+        - ./data/conf/nginx/:/etc/nginx/conf.d/:z
         - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z
         - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z
         - sogo-web-vol-1:/usr/lib/GNUstep/SOGo/:z
         - sogo-web-vol-1:/usr/lib/GNUstep/SOGo/:z
       ports:
       ports:
@@ -376,8 +378,8 @@ services:
         - SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n}
         - SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n}
         - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
         - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
       volumes:
       volumes:
-        - ./data/web/.well-known/acme-challenge:/var/www/acme:rw,z
-        - ./data/assets/ssl:/var/lib/acme/:rw,z
+        - ./data/web/.well-known/acme-challenge:/var/www/acme:z
+        - ./data/assets/ssl:/var/lib/acme/:z
         - ./data/assets/ssl-example:/var/lib/ssl-example/:ro,Z
         - ./data/assets/ssl-example:/var/lib/ssl-example/:ro,Z
         - mysql-socket-vol-1:/var/run/mysqld/:z
         - mysql-socket-vol-1:/var/run/mysqld/:z
       restart: always
       restart: always
@@ -525,7 +527,7 @@ services:
             - olefy
             - olefy
 
 
     ejabberd-mailcow:
     ejabberd-mailcow:
-      image: mailcow/ejabberd:1.1
+      image: mailcow/ejabberd:1.2
       volumes:
       volumes:
         - ./data/conf/ejabberd/ejabberd.yml:/home/ejabberd/conf/ejabberd.yml:z
         - ./data/conf/ejabberd/ejabberd.yml:/home/ejabberd/conf/ejabberd.yml:z
         - xmpp-vol-1:/home/ejabberd/database:z
         - xmpp-vol-1:/home/ejabberd/database:z