Merge branch 'master' into patch-1

This commit is contained in:
Bitti 2017-01-24 21:15:53 +01:00 committed by GitHub
commit ad9d9205e4
21 changed files with 461 additions and 95 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ data/conf/sogo/sieve.creds
data/conf/dovecot/dovecot-master.passwd
mailcow.conf
mailcow.conf_backup
data/conf/nginx/listen.active

View File

@ -13,6 +13,7 @@ RUN apt-get update
RUN apt-get install -y --no-install-recommends supervisor \
postfix \
sasl2-bin \
libsasl2-modules \
postfix \
postfix-mysql \
postfix-pcre \

View File

@ -1,7 +1,17 @@
#!/bin/bash
# Go in a 5 minute loop
while true; do
# Recreate view
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view"
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, senderacl, home) AS
SELECT mailbox.username, mailbox.domain, mailbox.username, mailbox.password, mailbox.name, mailbox.username, IFNULL(ga.aliases, ''), IFNULL(gda.ad_alias, ''), IFNULL(gs.send_as, ''), CONCAT('/var/vmail/', maildir) FROM mailbox
LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username = mailbox.username
LEFT OUTER JOIN grouped_sender_acl gs ON gs.username = mailbox.username
LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username
WHERE mailbox.active = '1';
EOF
# Wait for MySQL to warm-up
while ! mysqladmin ping --host mysql --silent; do
@ -22,6 +32,8 @@ while true; do
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_cache_folder</string>
<key>OCSEMailAlarmsFolderURL</key>
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_alarms_folder</string>
<key>DomainFieldName</key>
<string>domain</string>
<key>OCSFolderInfoURL</key>
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_folder_info</string>
<key>OCSSessionsFolderURL</key>
@ -43,7 +55,7 @@ EOF
echo " <key>${line}</key>
<dict>
<key>SOGoMailDomain</key>
<string>$(echo ${line} | tr '-' 'b' | tr '.' 'p')</string>
<string>${DOMAIN_SANE}</string>
<key>SOGoUserSources</key>
<array>
<dict>
@ -72,19 +84,10 @@ EOF
<key>userPasswordAlgorithm</key>
<string>ssha256</string>
<key>viewURL</key>
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_view_${DOMAIN_SANE}</string>
<string>mysql://${DBUSER}:${DBPASS}@mysql:3306/${DBNAME}/sogo_view</string>
</dict>
</array>
</dict>" >> /var/lib/sogo/GNUstep/Defaults/sogod.plist
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS sogo_view_${DOMAIN_SANE}"
mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF
CREATE VIEW sogo_view_${DOMAIN_SANE} (c_uid, c_name, c_password, c_cn, mail, aliases, ad_aliases, senderacl, home) AS
SELECT mailbox.username, mailbox.username, mailbox.password, mailbox.name, mailbox.username, IFNULL(ga.aliases, ''), IFNULL(gda.ad_alias, ''), IFNULL(gs.send_as, ''), CONCAT('/var/vmail/', maildir) FROM mailbox
LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username = mailbox.username
LEFT OUTER JOIN grouped_sender_acl gs ON gs.username = mailbox.username
LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username
WHERE mailbox.active = '1' AND domain = '${line}';
EOF
done < <(mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain;" -B -N)
# Generate footer
@ -96,6 +99,4 @@ done < <(mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain
chown sogo:sogo -R /var/lib/sogo/
chmod 600 /var/lib/sogo/GNUstep/Defaults/sogod.plist
sleep 300
done
sleep infinite

View File

@ -13,7 +13,9 @@ mail_location = maildir:~/
mail_plugins = quota acl zlib antispam
auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@
ssl_protocols = !SSLv3 !SSLv2
ssl_cipher_list = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA
ssl_prefer_server_ciphers = yes
ssl_cipher_list = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
ssl_options = no_compression
# Automatically regenerates every week
ssl_dh_parameters_length = 2048
log_timestamp = "%Y-%m-%d %H:%M:%S "

View File

@ -7,6 +7,18 @@ require "envelope";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
}
if envelope :detail :matches "to" "*" {
fileinto :create "INBOX/${1}";
if allof (
envelope :detail :matches "to" "*",
header :contains "X-Moo-Tag" "YES",
mailboxexists "INBOX/${s}"
) {
fileinto "INBOX/${s}";
}
elsif allof (
envelope :detail :matches "to" "*",
header :contains "X-Moo-Tag" "YES"
) {
set :lower "s" "${1}";
fileinto :create "INBOX/${s}";
}

View File

@ -5,9 +5,9 @@ server {
ssl_certificate_key /etc/ssl/mail/key.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ciphers 'EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA';
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
ssl_ecdh_curve secp384r1;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
index index.php index.html;
server_name _ autodiscover.* autoconfig.*;
error_log /var/log/nginx/error.log;
@ -27,6 +27,10 @@ server {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PHP_VALUE "max_execution_time = 1200
max_input_time = 1200
memory_limit = 64M";
fastcgi_read_timeout 1200;
}
rewrite ^(/save.+)$ /rspamd$1 last;
@ -53,7 +57,7 @@ server {
}
location ^~ /Microsoft-Server-ActiveSync {
proxy_pass http://sogo/SOGo/Microsoft-Server-ActiveSync;
proxy_pass http://sogo:20000/SOGo/Microsoft-Server-ActiveSync;
proxy_connect_timeout 1000;
proxy_next_upstream timeout error;
proxy_send_timeout 1000;

View File

@ -56,7 +56,7 @@ smtpd_error_sleep_time = 10s
smtpd_hard_error_limit = ${stress?1}${stress:5}
smtpd_helo_required = yes
smtpd_proxy_timeout = 600s
smtpd_recipient_restrictions = check_recipient_access proxy:mysql:/opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf, permit_sasl_authenticated, permit_mynetworks, reject_invalid_helo_hostname, reject_unknown_reverse_client_hostname, reject_unauth_destination
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, check_recipient_access proxy:mysql:/opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf, reject_invalid_helo_hostname, reject_unknown_reverse_client_hostname, reject_unauth_destination
smtpd_sasl_auth_enable = yes
smtpd_sasl_authenticated_header = yes
smtpd_sasl_path = inet:dovecot:10001
@ -69,12 +69,16 @@ smtpd_tls_dh1024_param_file = /etc/ssl/mail/dhparams.pem
smtpd_tls_eecdh_grade = strong
smtpd_tls_exclude_ciphers = ECDHE-RSA-RC4-SHA, RC4, aNULL
smtpd_tls_loglevel = 1
smtpd_tls_mandatory_ciphers = high
smtpd_tls_mandatory_exclude_ciphers = ECDHE-RSA-RC4-SHA, RC4, aNULL
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
smtp_tls_protocols = !SSLv2, !SSLv3
lmtp_tls_mandatory_protocols = !SSLv2, !SSLv3
lmtp_tls_protocols = !SSLv2, !SSLv3
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_tls_protocols = !SSLv2, !SSLv3
smtpd_tls_mandatory_ciphers = high
smtpd_tls_security_level = may
tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA
tls_ssl_options = NO_COMPRESSION
tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
virtual_alias_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_domain_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_domain_catchall_maps.cf
virtual_gid_maps = static:5000
virtual_mailbox_base = /var/vmail/
@ -86,3 +90,4 @@ virtual_uid_maps = static:5000
smtpd_milters = inet:rmilter:9900
non_smtpd_milters = inet:rmilter:9900
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
mydestination = localhost.localdomain, localhost

View File

@ -0,0 +1,22 @@
<?php
ini_set('error_reporting', 0);
header('Content-Type: text/plain');
require_once "vars.inc.php";
$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
$stmt = $pdo->query("SELECT `domain` FROM `domain`");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) {
echo strtolower(trim($row['domain'])) . PHP_EOL;
}
$stmt = $pdo->query("SELECT `alias_domain` FROM `alias_domain`");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) {
echo strtolower(trim($row['alias_domain'])) . PHP_EOL;
}
?>

View File

@ -0,0 +1,17 @@
<?php
ini_set('error_reporting', 0);
header('Content-Type: text/plain');
require_once "vars.inc.php";
$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
$stmt = $pdo->query("SELECT `username` FROM `mailbox` WHERE `wants_tagged_subject` = '1'");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) {
echo strtolower(trim($row['username'])) . PHP_EOL;
}
?>

View File

@ -10,3 +10,52 @@ rspamd_config.MAILCOW_AUTH = {
rspamd_config.MAILCOW_MOO = function (task)
return true
end
local modify_subject_map = rspamd_config:add_map({
url = 'http://nginx:8081/tags.php',
type = 'map',
description = 'Map of users to use subject tags for'
})
local auth_domain_map = rspamd_config:add_map({
url = 'http://nginx:8081/authoritative.php',
type = 'map',
description = 'Map of domains we are authoritative for'
})
rspamd_config.ADD_DELIMITER_TAG = {
callback = function(task)
local util = require("rspamd_util")
local rspamd_logger = require "rspamd_logger"
local user_tagged = task:get_recipients(1)[1]['user']
local domain = task:get_recipients(1)[1]['domain']
local user, tag = user_tagged:match("([^+]+)+(.*)")
local authdomain = auth_domain_map:get_key(domain)
if tag and authdomain then
rspamd_logger.infox("Domain %s is part of mailcow, start reading tag settings", domain)
local user_untagged = user .. '@' .. domain
rspamd_logger.infox("Querying tag settings for user %1", user_untagged)
if modify_subject_map:get_key(user_untagged) then
rspamd_logger.infox("User wants subject modified for tagged mail")
local sbj = task:get_header('Subject')
if tag then
rspamd_logger.infox("Found tag %1, will modify subject header", tag)
new_sbj = '=?UTF-8?B?' .. tostring(util.encode_base64('[' .. tag .. '] ' .. sbj)) .. '?='
task:set_rmilter_reply({
remove_headers = {['Subject'] = 1},
add_headers = {['Subject'] = new_sbj}
})
end
else
rspamd_logger.infox("Add X-Moo-Tag header")
task:set_rmilter_reply({
add_headers = {['X-Moo-Tag'] = 'YES'}
})
end
else
rspamd_logger.infox("Skip delimiter handling for untagged message or authenticated user")
end
return false
end
}

View File

@ -1,17 +1,17 @@
<?php
if ($_SESSION['mailcow_cc_role'] == "admin"):
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin"):
?>
<div id="RestartSOGo" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Restart SOGo</h4>
<h4 class="modal-title"><?=$lang['footer']['restart_sogo'];?></h4>
</div>
<div class="modal-body">
<p>Some tasks, e.g. adding a domain, require you to restart SOGo to catch changes made in the mailcow UI.</p>
<p><?=$lang['footer']['restart_sogo_info'];?></p>
<hr />
<button class="btn btn-md btn-primary" id="triggerRestartSogo">Restart SOGo</button>
<button class="btn btn-md btn-primary" id="triggerRestartSogo"><?=$lang['footer']['restart_now'];?></button>
<br /><br />
<div id="statusTriggerRestartSogo"></div>
</div>
@ -85,6 +85,7 @@ $(document).ready(function() {
// Trigger SOGo restart
$('#triggerRestartSogo').click(function(){
$(this).prop("disabled",true);
$(this).html('<span class="glyphicon glyphicon-refresh glyphicon-spin"></span> ');
$('#statusTriggerRestartSogo').text('Stopping SOGo workers, this may take a while... ');
$.ajax({
method: 'get',
@ -105,6 +106,7 @@ $(document).ready(function() {
},
success: function(data) {
$('#statusTriggerRestartSogo').append(data);
$('#triggerRestartSogo').html('<span class="glyphicon glyphicon-ok"></span> ');
}
});
}

View File

@ -8,11 +8,12 @@ function hasDomainAccess($username, $role, $domain) {
if (!filter_var($username, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) {
return false;
}
if (!is_valid_domain_name($domain)) {
return false;
}
if ($role != 'admin' && $role != 'domainadmin' && $role != 'user') {
return false;
}
try {
$stmt = $pdo->prepare("SELECT `domain` FROM `domain_admins`
WHERE (
@ -51,6 +52,7 @@ function init_db_schema() {
$data = '';
}
}
// Create index if not exists
$stmt = $pdo->query("SHOW INDEX FROM sogo_acl WHERE KEY_NAME = 'sogo_acl_c_folder_id_idx'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
@ -66,6 +68,22 @@ function init_db_schema() {
'msg' => 'Database initialization completed.'
);
}
// Add newly added columns
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'kind'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `mailbox` ADD `kind` varchar(100) NOT NULL DEFAULT ''");
}
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'multiple_bookings'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `mailbox` ADD `multiple_bookings` tinyint(1) NOT NULL DEFAULT '0'");
}
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'wants_tagged_subject'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `mailbox` ADD `wants_tagged_subject` tinyint(1) NOT NULL DEFAULT '0'");
}
}
function verify_ssha256($hash, $password) {
// Remove tag if any
@ -2192,6 +2210,9 @@ function delete_domain_admin($postarray) {
function get_spam_score($username) {
global $pdo;
$default = "5, 15";
if ($_SESSION['mailcow_cc_role'] != "user") {
return false;
}
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
return $default;
}
@ -2235,6 +2256,13 @@ function get_spam_score($username) {
function set_spam_score($postarray) {
global $lang;
global $pdo;
if ($_SESSION['mailcow_cc_role'] != "user") {
$_SESSION['return'] = array(
'type' => 'danger',
'msg' => sprintf($lang['danger']['access_denied'])
);
return false;
}
$username = $_SESSION['mailcow_cc_username'];
$lowspamlevel = explode(',', $postarray['score'])[0];
$highspamlevel = explode(',', $postarray['score'])[1];
@ -2288,7 +2316,15 @@ function set_spam_score($postarray) {
function set_policy_list($postarray) {
global $lang;
global $pdo;
if ($_SESSION['mailcow_cc_role'] != "admin" &&
$_SESSION['mailcow_cc_role'] != "domainadmin" &&
$_SESSION['mailcow_cc_role'] != "user") {
$_SESSION['return'] = array(
'type' => 'danger',
'msg' => sprintf($lang['danger']['access_denied'])
);
return false;
}
(isset($postarray['domain'])) ? $object = $postarray['domain'] : $object = $_SESSION['mailcow_cc_username'];
($postarray['object_list'] == "bl") ? $object_list = "blacklist_from" : $object_list = "whitelist_from";
$object_from = preg_replace('/\.+/', '.', rtrim(preg_replace("/\.\*/", "*", trim(strtolower($postarray['object_from']))), '.'));
@ -2389,6 +2425,13 @@ function set_policy_list($postarray) {
function set_tls_policy($postarray) {
global $lang;
global $pdo;
if ($_SESSION['mailcow_cc_role'] != "user") {
$_SESSION['return'] = array(
'type' => 'danger',
'msg' => sprintf($lang['danger']['access_denied'])
);
return false;
}
isset($postarray['tls_in']) ? $tls_in = '1' : $tls_in = '0';
isset($postarray['tls_out']) ? $tls_out = '1' : $tls_out = '0';
$username = $_SESSION['mailcow_cc_username'];
@ -2422,6 +2465,9 @@ function set_tls_policy($postarray) {
function get_tls_policy($username) {
global $lang;
global $pdo;
if ($_SESSION['mailcow_cc_role'] != "user") {
return false;
}
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'] = array(
'type' => 'danger',
@ -2601,6 +2647,101 @@ function get_sender_acl_handles($mailbox, $which) {
}
return false;
}
function tagging_options($action, $data = null) {
global $lang;
global $pdo;
$username = $_SESSION['mailcow_cc_username'];
if ($action == "get") {
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
return false;
}
try {
$stmt = $pdo->prepare("SELECT `wants_tagged_subject` FROM `mailbox` WHERE `username` = :username");
$stmt->execute(array(':username' => $username));
$SelectData = $stmt->fetch(PDO::FETCH_ASSOC);
}
catch(PDOException $e) {
$_SESSION['return'] = array(
'type' => 'danger',
'msg' => 'MySQL: '.$e
);
return false;
}
return $SelectData['wants_tagged_subject'];
}
elseif ($action == "set") {
($data['tagged_mail_handler'] == "subject") ? $wants_tagged_subject = '1' : $wants_tagged_subject = '0';
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'] = array(
'type' => 'danger',
'msg' => sprintf($lang['danger']['username_invalid'])
);
return false;
}
try {
$stmt = $pdo->prepare("UPDATE `mailbox` SET `wants_tagged_subject` = :wants_tagged_subject WHERE `username` = :username");
$stmt->execute(array(':username' => $username, ':wants_tagged_subject' => $wants_tagged_subject));
$SelectData = $stmt->fetch(PDO::FETCH_ASSOC);
}
catch(PDOException $e) {
$_SESSION['return'] = array(
'type' => 'danger',
'msg' => 'MySQL: '.$e
);
return false;
}
$_SESSION['return'] = array(
'type' => 'success',
'msg' => sprintf($lang['success']['mailbox_modified'], $username)
);
}
return false;
}
function user_object_info($action, $data = null) {
global $lang;
global $pdo;
$username = $_SESSION['mailcow_cc_username'];
if ($action == "get") {
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
return false;
}
try {
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '&#10008;') AS `aliases` FROM `alias` WHERE `goto` = :username_goto AND `address` NOT LIKE '@%' AND `address` != :username_address");
$stmt->execute(array(':username_goto' => $username, ':username_address' => $username));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) {
$data['aliases'] = $row['aliases'];
}
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`send_as` SEPARATOR ', '), '&#10008;') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `send_as` NOT LIKE '@%';");
$stmt->execute(array(':username' => $username));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) {
$data['aliases_also_send_as'] = $row['send_as'];
}
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`send_as` SEPARATOR ', '), '&#10008;') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `send_as` LIKE '@%';");
$stmt->execute(array(':username' => $username));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) {
$data['aliases_send_as_all'] = $row['send_as'];
}
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '&#10008;') as `address` FROM `alias` WHERE `goto` = :username AND `address` LIKE '@%';");
$stmt->execute(array(':username' => $username));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) {
$data['is_catch_all'] = $row['address'];
}
return $data;
}
catch(PDOException $e) {
$_SESSION['return'] = array(
'type' => 'danger',
'msg' => 'MySQL: '.$e
);
return false;
}
}
return false;
}
function is_valid_domain_name($domain_name) {
if (empty($domain_name)) {
return false;

View File

@ -119,6 +119,30 @@ table[data-sortable].sortable-theme-bootstrap.sortable-theme-bootstrap-striped t
background-color: #fafafa;
border:1px solid white;
}
.glyphicon-spin {
-webkit-animation: spin 1000ms infinite linear;
animation: spin 1000ms infinite linear;
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
</style>
<?php
if (preg_match("/mailbox.php/i", $_SERVER['REQUEST_URI'])):
@ -202,7 +226,7 @@ endif;
<?php
if ($_SESSION['mailcow_cc_role'] == "admin"):
?>
<li><a href data-toggle="modal" data-target="#RestartSOGo"><span style="font-size:12px" class="glyphicon glyphicon-refresh" aria-hidden="true"></span> Restart SOGo</a></li>
<li><a href data-toggle="modal" data-target="#RestartSOGo"><span style="font-size:12px" class="glyphicon glyphicon-refresh" aria-hidden="true"></span> <?=$lang['header']['restart_sogo'];?></a></li>
<?php
endif;
?>

View File

@ -78,6 +78,9 @@ CREATE TABLE IF NOT EXISTS `mailbox` (
`modified` datetime NOT NULL DEFAULT '2016-01-01 00:00:00',
`tls_enforce_in` tinyint(1) NOT NULL DEFAULT '0',
`tls_enforce_out` tinyint(1) NOT NULL DEFAULT '0',
`kind` varchar(100) NOT NULL DEFAULT '',
`multiple_bookings` tinyint(1) NOT NULL DEFAULT '0',
`wants_tagged_subject` tinyint(1) NOT NULL DEFAULT '0',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`username`),
KEY `domain` (`domain`)

View File

@ -51,6 +51,9 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "user
if (isset($_POST["trigger_set_spam_score"])) {
set_spam_score($_POST);
}
if (isset($_POST["trigger_set_tagging_options"])) {
tagging_options('set', $_POST);
}
if (isset($_POST["trigger_set_policy_list"])) {
set_policy_list($_POST);
}

View File

@ -15,7 +15,6 @@ $database_name = getenv('DBNAME');
// Other variables
$mailcow_hostname = getenv('MAILCOW_HOSTNAME');
date_default_timezone_set(getenv('TZ'));
// Where to go after adding and editing objects
// Can be "form" or "previous"

View File

@ -5,7 +5,10 @@
//
*/
$lang['footer']['loading'] = 'Einen Moment bitte...';
$lang['getmail']['no_status'] = 'Keinen letzten Vorgang festgestellt.';
$lang['header']['restart_sogo'] = 'SOGo neustarten';
$lang['footer']['restart_sogo'] = 'SOGo neustarten';
$lang['footer']['restart_now'] = 'Jetzt neustarten';
$lang['footer']['restart_sogo_info'] = 'Einige Änderungen an Domains benötigen einen Neustart SOGos. Hier können Sie SOGo neustarten.<br /><br /><b>Wichtig:</b> Ein korrekter Neustart SOGos kann eine Weile in Anspruch nehmen, bitte warten Sie, bis der Prozess vollständig beendet wurde.';
$lang['dkim']['confirm'] = 'Sind Sie sicher?';
$lang['danger']['dkim_not_found'] = 'DKIM-Record nicht gefunden';
$lang['danger']['dkim_remove_failed'] = 'Kann DKIM-Record nicht entfernen';
@ -99,6 +102,8 @@ $lang['user']['did_you_know'] = '<b>Wussten Sie schon?</b> Sie können Ihre E-Ma
$lang['user']['spam_aliases'] = 'Temporäre E-Mail Aliasse';
$lang['user']['alias'] = 'Alias';
$lang['user']['aliases'] = 'Aliasse';
$lang['user']['is_catch_all'] = 'Ist Catch-All Adresse für Domain(s)';
$lang['user']['aliases_also_send_as'] = 'Darf außerdem versenden als';
$lang['user']['aliases_send_as_all'] = 'Absender für folgende Domains nicht prüfen';
$lang['user']['alias_create_random'] = 'Zufälligen Alias generieren';
$lang['user']['alias_extend_all'] = 'Gültigkeit +1h';
@ -138,6 +143,14 @@ $lang['user']['no_record'] = 'Kein Eintrag';
$lang['user']['misc_settings'] = 'Sonstige Kontoeinstellungen';
$lang['user']['misc_delete_profile'] = 'Sonstige Kontoeinstellungen';
$lang['user']['tag_handling'] = 'Umgang mit getaggten E-Mails steuern';
$lang['user']['tag_in_subfolder'] = 'In Unterordner';
$lang['user']['tag_in_subject'] = 'In Betreff';
$lang['user']['tag_help_explain'] = 'Als Unterordner: Es wird ein Ordner mit dem Namen des Tags unterhalb der Inbox erstellt ("INBOX/Facebook").<br />
In Betreff: Der Name des Tags wird dem Betreff angefügt, etwa "[Facebook] Meine Neuigkeiten".';
$lang['user']['tag_help_example'] = 'Beispiel für eine getaggte E-Mail-Adresse: ich<b>+Facebook</b>@example.org';
$lang['start']['dashboard'] = '%s - Dashboard';
$lang['start']['start_rc'] = 'Roundcube öffnen';
$lang['start']['start_sogo'] = 'SOGo öffnen';

View File

@ -5,7 +5,10 @@
//
*/
$lang['footer']['loading'] = "Please wait...";
$lang['getmail']['no_status'] = "No previous status found.";
$lang['header']['restart_sogo'] = 'Restart SOGo';
$lang['footer']['restart_sogo'] = 'Restart SOGo';
$lang['footer']['restart_now'] = 'Restart now';
$lang['footer']['restart_sogo_info'] = 'Some tasks, e.g. adding a domain, require you to restart SOGo to catch changes made in the mailcow UI.<br /><br /><b>Important:</b> A graceful restart may take a while to complete, please wait for it to finish.';
$lang['dkim']['confirm'] = "Are you sure?";
$lang['danger']['dkim_not_found'] = "DKIM record not found";
$lang['danger']['dkim_remove_failed'] = "Cannot remove selected DKIM record";
@ -100,6 +103,10 @@ $lang['user']['new_password_description'] = 'Requirement: 6 characters long, let
$lang['user']['did_you_know'] = '<b>Did you know?</b> You can use tags in your email address ("me+<b>privat</b>@example.com") to move messages to a folder automatically (example: "privat").';
$lang['user']['spam_aliases'] = 'Temporary email aliases';
$lang['user']['alias'] = 'Alias';
$lang['user']['aliases'] = 'Aliases';
$lang['user']['is_catch_all'] = 'Catch-all for domain/s';
$lang['user']['aliases_also_send_as'] = 'Also allowed to send as';
$lang['user']['aliases_send_as_all'] = 'Do not check sender access for following domains';
$lang['user']['alias_create_random'] = 'Generate random alias';
$lang['user']['alias_extend_all'] = 'Extend aliases by 1 hour';
$lang['user']['alias_valid_until'] = 'Valid until';
@ -138,6 +145,14 @@ $lang['user']['no_record'] = 'No Record';
$lang['user']['misc_settings'] = 'Other profile settings';
$lang['user']['misc_delete_profile'] = 'Other profile settings';
$lang['user']['tag_handling'] = 'Set handling for tagged mail';
$lang['user']['tag_in_subfolder'] = 'In subfolder';
$lang['user']['tag_in_subject'] = 'In subject';
$lang['user']['tag_help_explain'] = 'In subfolder: a new subfolder named after the tag will be created below INBOX ("INBOX/Facebook").<br />
In subject: the tags name will be prepended to the mails subject, example: "[Facebook] Meine Neuigkeiten".';
$lang['user']['tag_help_example'] = 'Example for a tagged email address: ich<b>+Facebook</b>@example.org';
$lang['start']['dashboard'] = '%s - dashboard';
$lang['start']['start_rc'] = 'Open Roundcube';
$lang['start']['start_sogo'] = 'Open SOGo';

View File

@ -26,13 +26,13 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
<div class="form-group">
<label class="control-label col-sm-3" for="user_new_pass"><?=$lang['user']['new_password'];?></label>
<div class="col-sm-5">
<input type="password" class="form-control" pattern="(?=.*[A-Za-z])(?=.*[0-9])\w{6,}" name="user_new_pass" id="user_new_pass" autocomplete="off" disabled="disabled">
<input type="password" class="form-control" pattern=".{6,}" name="user_new_pass" id="user_new_pass" autocomplete="off" disabled="disabled" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="user_new_pass2"><?=$lang['user']['new_password_repeat'];?></label>
<div class="col-sm-5">
<input type="password" class="form-control" pattern="(?=.*[A-Za-z])(?=.*[0-9])\w{6,}" name="user_new_pass2" id="user_new_pass2" disabled="disabled" autocomplete="off">
<input type="password" class="form-control" pattern=".{6,}" name="user_new_pass2" id="user_new_pass2" disabled="disabled" autocomplete="off" required>
<p class="help-block"><?=$lang['user']['new_password_description'];?></p>
</div>
</div>
@ -50,6 +50,50 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
</div>
</div>
</form>
<hr>
<?php // Get user information about aliases
$get_user_object_info = user_object_info('get');?>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases'];?>:</div>
<div class="col-md-9 col-xs-7">
<p><?=$get_user_object_info['aliases'];?></p>
</div>
</div>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_also_send_as'];?>:</div>
<div class="col-md-9 col-xs-7">
<p><?=$get_user_object_info['aliases_also_send_as'];?></p>
</div>
</div>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases_send_as_all'];?>:</div>
<div class="col-md-9 col-xs-7">
<p><?=$get_user_object_info['aliases_send_as_all'];?></p>
</div>
</div>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['is_catch_all'];?>:</div>
<div class="col-md-9 col-xs-7">
<p><?=$get_user_object_info['is_catch_all'];?></p>
</div>
</div>
<hr>
<?php // Show tagging options ?>
<form class="form-horizontal" role="form" method="post">
<?php $get_tagging_options = tagging_options('get');?>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['tag_handling'];?>:</div>
<div class="col-md-9 col-xs-7">
<input type="hidden" name="trigger_set_tagging_options" value="1">
<select name="tagged_mail_handler" class="selectpicker" onchange="this.form.submit()">
<option value="subfolder" <?=($get_tagging_options == "0") ? 'selected' : null; ?>><?=$lang['user']['tag_in_subfolder'];?></option>
<option value="subject" <?=($get_tagging_options == "1") ? 'selected' : null; ?>><?=$lang['user']['tag_in_subject'];?></option>
</select>
<p class="help-block"><?=$lang['user']['tag_help_explain'];?></p>
<p class="help-block"><?=$lang['user']['tag_help_example'];?></p>
</div>
</div>
</form>
</div>
</div>
@ -321,8 +365,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
</form>
</div>
</div>
<br />
</div> <!-- /container -->
<script src="js/sorttable.js"></script>
<script src="js/user.js"></script>

View File

@ -58,6 +58,7 @@ services:
- ./data/conf/rspamd/local.d/:/etc/rspamd/local.d:ro
- ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro
- dkim-vol-1:/data/dkim
- rspamd-vol-1:/var/lib/rspamd
restart: always
dns:
- 172.22.1.254
@ -69,6 +70,7 @@ services:
php-fpm-mailcow:
image: andryyy/mailcow-dockerized:phpfpm
command: "php-fpm -d date.timezone=${TZ}"
depends_on:
- pdns-mailcow
volumes:
@ -83,7 +85,6 @@ services:
- DBUSER=${DBUSER}
- DBPASS=${DBPASS}
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
- TZ=${TZ}
restart: always
networks:
mailcow-network:
@ -234,3 +235,4 @@ volumes:
mysql-vol-1:
dkim-vol-1:
redis-vol-1:
rspamd-vol-1:

View File

@ -12,10 +12,16 @@ if [[ -f mailcow.conf ]]; then
esac
fi
read -p "Hostname (FQDN): " -ei "mx.example.org" MAILCOW_HOSTNAME
read -p "Timezone: " -ei "Europe/Berlin" TZ
if [ -z "$MAILCOW_LANGUAGE" ]; then
read -p "WebUI Default Language: " -ei "en/pt/de/nl" MAILCOW_LANGUAGE
fi
if [ -z "$MAILCOW_HOSTNAME" ]; then
read -p "Hostname (FQDN): " -ei "mx.example.org" MAILCOW_HOSTNAME
fi
if [ -z "$TZ" ]; then
read -p "Timezone: " -ei "Europe/Berlin" TZ
fi
cat << EOF > data/web/inc/vars.local.inc.php
<?php
error_reporting(0);
@ -27,6 +33,7 @@ PLEASE USE THIS FILE TO OVERWRITE "vars.inc.php" SETTINGS AND MAKE THEM PERSIST
$DEFAULT_LANG = "${MAILCOW_LANGUAGE}";
EOF
cat << EOF > mailcow.conf
# ------------------------------
# mailcow web ui configuration