[Ejabberd] More fixes for Ejabberd integration (WIP)

master
andryyy 2021-02-12 10:04:19 +01:00
parent 2bac898a15
commit f2453e316f
No known key found for this signature in database
GPG Key ID: 8EC34FF2794E25EF
7 changed files with 118 additions and 35 deletions

View File

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

View File

@ -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

View File

@ -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,

View File

@ -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'); $hosts_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
if (!$map_handle) { 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($hosts_handle, '# Autogenerated by mailcow' . PHP_EOL);
fwrite($map_handle, 'hosts:' . 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'); $acl_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
if (!$map_handle) { 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($acl_handle, '# Autogenerated by mailcow' . PHP_EOL);
fwrite($map_handle, 'append_host_config:' . 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($acl_handle, ' ' . $xmpp_domains[$domain]['xmpp_host'] . ':' . PHP_EOL);
fwrite($map_handle, ' acl:' . PHP_EOL); fwrite($acl_handle, ' acl:' . PHP_EOL);
fwrite($map_handle, ' admin:' . PHP_EOL); fwrite($acl_handle, ' admin:' . PHP_EOL);
fwrite($map_handle, ' user:' . 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'); $hosts_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
if (!$map_handle) { 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($hosts_handle, '# Autogenerated by mailcow' . PHP_EOL);
fclose($map_handle); fclose($hosts_handle);
// Write empty ACL file // Write empty ACL file
$map_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w'); $acl_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
if (!$map_handle) { 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($acl_handle, '# Autogenerated by mailcow' . PHP_EOL);
fclose($map_handle); 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(

View File

@ -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",

View File

@ -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",

View File

@ -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/web/.well-known/acme-challenge:/var/www/acme:z
- ./data/assets/ssl:/var/lib/acme/:rw,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