Merge branch 'dev'

This commit is contained in:
andryyy 2017-07-05 12:05:09 +02:00
commit c30f54d368
20 changed files with 154 additions and 260 deletions

View File

@ -137,10 +137,11 @@ while true; do
fi fi
done done
ALL_VALIDATED="$(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} ${VALIDATED_MAILCOW_HOSTNAME})" # Unique elements
ALL_VALIDATED=($(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} ${VALIDATED_MAILCOW_HOSTNAME} | xargs -n1 | sort -u | xargs))
if [[ -z ${ALL_VALIDATED[*]} ]]; then if [[ -z ${ALL_VALIDATED[*]} ]]; then
echo "Cannot validate hostnames, skipping Let's Encrypt..." echo "Cannot validate hostnames, skipping Let's Encrypt..."
echo 0 exit 0
fi fi
ORPHANED_SAN=($(echo ${SAN_ARRAY_NOW[*]} ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} ${MAILCOW_HOSTNAME} | tr ' ' '\n' | sort | uniq -u )) ORPHANED_SAN=($(echo ${SAN_ARRAY_NOW[*]} ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} ${MAILCOW_HOSTNAME} | tr ' ' '\n' | sort | uniq -u ))
@ -159,7 +160,7 @@ while true; do
-f ${ACME_BASE}/acme/private/account.key \ -f ${ACME_BASE}/acme/private/account.key \
-k ${ACME_BASE}/acme/private/privkey.pem \ -k ${ACME_BASE}/acme/private/privkey.pem \
-c ${ACME_BASE}/acme \ -c ${ACME_BASE}/acme \
${VALIDATED_MAILCOW_HOSTNAME} ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} ${ALL_VALIDATED[*]}
case "$?" in case "$?" in
0) # new certs 0) # new certs

View File

@ -4,6 +4,11 @@ trap "kill 0" SIGINT
touch /var/log/clamav/clamd.log /var/log/clamav/freshclam.log touch /var/log/clamav/clamd.log /var/log/clamav/freshclam.log
chown -R clamav:clamav /var/log/clamav/ chown -R clamav:clamav /var/log/clamav/
if [[ "${SKIP_CLAMD}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "SKIP_CLAMD=y, skipping ClamAV..."
exit 0
fi
freshclam -d & freshclam -d &
clamd & clamd &

View File

@ -15,17 +15,27 @@ source s_src {
}; };
destination d_combined { file("/var/log/combined.log"); }; destination d_combined { file("/var/log/combined.log"); };
destination d_redis { destination d_redis_persistent_log {
redis( redis(
host("redis-mailcow") host("redis-mailcow")
persist-name("redis1")
port(6379) port(6379)
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n") command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
); );
}; };
filter f_mail { facility(mail) and not filter(f_debug); }; destination d_redis_f2b_channel {
redis(
host("redis-mailcow")
persist-name("redis2")
port(6379)
command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
);
};
filter f_mail { facility(mail); };
log { log {
source(s_src); source(s_src);
destination(d_combined); destination(d_combined);
filter(f_mail); filter(f_mail);
destination(d_redis); destination(d_redis_persistent_log);
destination(d_redis_f2b_channel);
}; };

View File

@ -2,7 +2,7 @@ FROM python:2-alpine
LABEL maintainer "Andre Peters <andre.peters@servercow.de>" LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
RUN apk add -U --no-cache iptables ip6tables RUN apk add -U --no-cache iptables ip6tables
RUN pip install docker redis RUN pip install redis ipaddress
COPY logwatch.py / COPY logwatch.py /
CMD ["python2", "-u", "/logwatch.py"] CMD ["python2", "-u", "/logwatch.py"]

View File

@ -8,7 +8,6 @@ import signal
import ipaddress import ipaddress
import subprocess import subprocess
from threading import Thread from threading import Thread
import docker
import redis import redis
import time import time
import json import json
@ -19,33 +18,16 @@ if re.search(yes_regex, os.getenv('SKIP_FAIL2BAN', 0)):
raise SystemExit raise SystemExit
r = redis.StrictRedis(host='172.22.1.249', decode_responses=True, port=6379, db=0) r = redis.StrictRedis(host='172.22.1.249', decode_responses=True, port=6379, db=0)
client = docker.from_env() pubsub = r.pubsub()
for container in client.containers.list():
if "postfix-mailcow" in container.name:
postfix_container = container.name
elif "dovecot-mailcow" in container.name:
dovecot_container = container.name
elif "sogo-mailcow" in container.name:
sogo_container = container.name
elif "php-fpm-mailcow" in container.name:
php_fpm_container = container.name
RULES = {} RULES = {}
RULES[1] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed'
RULES[postfix_container] = {} RULES[2] = '-login: Disconnected \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),'
RULES[dovecot_container] = {} RULES[3] = '-login: Disconnected \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
RULES[sogo_container] = {} RULES[4] = '-login: Aborted login \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
RULES[php_fpm_container] = {} RULES[5] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
RULES[6] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
RULES[postfix_container][1] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .* authentication failed' RULES[7] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
RULES[dovecot_container][1] = '-login: Disconnected \(auth failed, .*\): user=.*, method=.*, rip=([0-9a-f\.:]+),'
RULES[dovecot_container][2] = '-login: Disconnected \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
RULES[dovecot_container][3] = '-login: Aborted login \(no auth .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
RULES[dovecot_container][4] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
RULES[sogo_container][1] = 'SOGo.* Login from \'([0-9a-f\.:]+)\' for user .* might not have worked'
RULES[php_fpm_container][1] = 'mailcow UI: Invalid password for .* by ([0-9a-f\.:]+)'
r.setnx("F2B_BAN_TIME", "1800") r.setnx("F2B_BAN_TIME", "1800")
r.setnx("F2B_MAX_ATTEMPTS", "10") r.setnx("F2B_MAX_ATTEMPTS", "10")
@ -149,24 +131,28 @@ def clear():
print "Clearing all bans" print "Clearing all bans"
for net in bans.copy(): for net in bans.copy():
unban(net) unban(net)
pubsub.unsubscribe()
def watch(container): def watch():
log['time'] = int(round(time.time())) log['time'] = int(round(time.time()))
log['priority'] = "info" log['priority'] = "info"
log['message'] = "Watching %s" % container log['message'] = "Watching Redis channel F2B_CHANNEL"
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False)) r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
print "Watching", container pubsub.subscribe("F2B_CHANNEL")
for msg in client.containers.get(container).attach(stream=True, logs=False): print "Subscribing to Redis channel F2B_CHANNEL"
for rule_id, rule_regex in RULES[container].iteritems(): while True:
result = re.search(rule_regex, msg) for item in pubsub.listen():
if result: for rule_id, rule_regex in RULES.iteritems():
addr = result.group(1) if item['data'] and item['type'] == 'message':
print "%s matched rule id %d in %s" % (addr, rule_id, container) result = re.search(rule_regex, item['data'])
log['time'] = int(round(time.time())) if result:
log['priority'] = "warn" addr = result.group(1)
log['message'] = "%s matched rule id %d in %s" % (addr, rule_id, container) print "%s matched rule id %d" % (addr, rule_id)
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False)) log['time'] = int(round(time.time()))
ban(addr) log['priority'] = "warn"
log['message'] = "%s matched rule id %d" % (addr, rule_id)
r.lpush("F2B_LOG", json.dumps(log, ensure_ascii=False))
ban(addr)
def autopurge(): def autopurge():
while not quit_now: while not quit_now:
@ -180,14 +166,13 @@ def autopurge():
if bans[net]['attempts'] >= MAX_ATTEMPTS: if bans[net]['attempts'] >= MAX_ATTEMPTS:
if time.time() - bans[net]['last_attempt'] > BAN_TIME: if time.time() - bans[net]['last_attempt'] > BAN_TIME:
unban(net) unban(net)
time.sleep(30) time.sleep(10)
if __name__ == '__main__': if __name__ == '__main__':
threads = []
for container in RULES: watch_thread = Thread(target=watch)
threads.append(Thread(target=watch, args=(container,))) watch_thread.daemon = True
threads[-1].daemon = True watch_thread.start()
threads[-1].start()
autopurge_thread = Thread(target=autopurge) autopurge_thread = Thread(target=autopurge)
autopurge_thread.daemon = True autopurge_thread.daemon = True
@ -197,9 +182,4 @@ if __name__ == '__main__':
atexit.register(clear) atexit.register(clear)
while not quit_now: while not quit_now:
for thread in threads: time.sleep(0.5)
if not thread.isAlive():
break
time.sleep(0.1)
clear()

View File

@ -15,17 +15,27 @@ source s_src {
}; };
destination d_combined { file("/var/log/combined.log"); }; destination d_combined { file("/var/log/combined.log"); };
destination d_redis { destination d_redis_persistent_log {
redis( redis(
host("redis-mailcow") host("redis-mailcow")
persist-name("redis1")
port(6379) port(6379)
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n") command("LPUSH" "POSTFIX_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
); );
}; };
filter f_mail { facility(mail) and not filter(f_debug); }; destination d_redis_f2b_channel {
redis(
host("redis-mailcow")
persist-name("redis2")
port(6379)
command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
);
};
filter f_mail { facility(mail); };
log { log {
source(s_src); source(s_src);
destination(d_combined); destination(d_combined);
filter(f_mail); filter(f_mail);
destination(d_redis); destination(d_redis_persistent_log);
destination(d_redis_f2b_channel);
}; };

View File

@ -1,4 +1,4 @@
FROM debian:jessie-slim FROM debian:stretch-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>" LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
@ -11,30 +11,23 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \ ca-certificates \
cron \ cron \
gnupg \ gnupg \
make \
mysql-client \ mysql-client \
supervisor \ supervisor \
syslog-ng \ syslog-ng \
syslog-ng-core \ syslog-ng-core \
syslog-ng-mod-redis \ syslog-ng-mod-redis \
tar \ dirmngr \
wget \ wget \
zip \
&& rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/apt/lists/* \
&& dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \ && dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \ && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
&& wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc" \
&& export GNUPGHOME="$(mktemp -d)" \
&& gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
&& gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
&& rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc \
&& chmod +x /usr/local/bin/gosu \ && chmod +x /usr/local/bin/gosu \
&& gosu nobody true && gosu nobody true
RUN mkdir /usr/share/doc/sogo \ RUN mkdir /usr/share/doc/sogo \
&& touch /usr/share/doc/sogo/empty.sh \ && touch /usr/share/doc/sogo/empty.sh \
&& apt-key adv --keyserver keys.gnupg.net --recv-key 0x810273C4 \ && apt-key adv --keyserver sks.labs.nic.cz --recv-key A04BE668 \
&& echo "deb http://packages.inverse.ca/SOGo/nightly/3/debian/ jessie jessie" > /etc/apt/sources.list.d/sogo.list \ && echo "deb http://www.axis.cz/linux/debian stretch sogo-v3" > /etc/apt/sources.list.d/sogo.list \
&& apt-get update && apt-get install -y --force-yes \ && apt-get update && apt-get install -y --force-yes \
sogo \ sogo \
sogo-activesync \ sogo-activesync \

View File

@ -93,9 +93,6 @@ echo ' </dict>
chown sogo:sogo -R /var/lib/sogo/ chown sogo:sogo -R /var/lib/sogo/
chmod 600 /var/lib/sogo/GNUstep/Defaults/sogod.plist chmod 600 /var/lib/sogo/GNUstep/Defaults/sogod.plist
# Regenerate the SOGo Integrator plugin
/thunderbird/build-plugins.sh ${MAILCOW_HOSTNAME} < <(mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain;" -B -N)
supervisorctl restart sogo supervisorctl restart sogo
sleep 99999 sleep 99999

View File

@ -19,13 +19,22 @@ source s_sogo {
destination d_combined { destination d_combined {
file("/var/log/combined.log"); file("/var/log/combined.log");
}; };
destination d_redis { destination d_redis_persistent_log {
redis( redis(
host("redis-mailcow") host("redis-mailcow")
persist-name("redis1")
port(6379) port(6379)
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n") command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
); );
}; };
destination d_redis_f2b_channel {
redis(
host("redis-mailcow")
persist-name("redis2")
port(6379)
command("PUBLISH" "F2B_CHANNEL" "$MESSAGE")
);
};
log { log {
source(s_sogo); source(s_sogo);
source(s_src); source(s_src);
@ -33,5 +42,6 @@ log {
}; };
log { log {
source(s_sogo); source(s_sogo);
destination(d_redis); destination(d_redis_persistent_log);
destination(d_redis_f2b_channel);
}; };

View File

@ -231,7 +231,7 @@ $tfa_data = get_tfa();
<button class="btn btn-default" id="add_item" data-id="dkim" data-api-url='add/dkim' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button> <button class="btn btn-default" id="add_item" data-id="dkim" data-api-url='add/dkim' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button>
</form> </form>
<legend data-target="#import_dkim" style="margin-top:40px;cursor:pointer" data-toggle="collapse"> <?=$lang['admin']['import_private_key'];?></legend> <legend data-target="#import_dkim" style="margin-top:40px;cursor:pointer" id="import_dkim_legend" unselectable="on" data-toggle="collapse"><span id="import_dkim_arrow" class="rotate glyphicon glyphicon-menu-down"></span> <?=$lang['admin']['import_private_key'];?></legend>
<div id="import_dkim" class="collapse"> <div id="import_dkim" class="collapse">
<form class="form" data-id="dkim_import" role="form" method="post"> <form class="form" data-id="dkim_import" role="form" method="post">
<div class="form-group"> <div class="form-group">

View File

@ -31,3 +31,14 @@ body.modal-open {
.inputMissingAttr { .inputMissingAttr {
border-color: #FF4136; border-color: #FF4136;
} }
.rotate {
-moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear;
transition: all 0.3s linear;
}
.rotate.animation {
-ms-transform:rotateX(180deg);
-moz-transform:rotateX(180deg);
-webkit-transform:rotateX(180deg);
transform:rotateX(180deg);
}

View File

@ -91,4 +91,11 @@ body.modal-open {
max-width: 550px; max-width: 550px;
z-index: 2000; z-index: 2000;
} }
.input-group-sm .btn { margin-top: 0px !important } .input-group-sm .btn { margin-top: 0px !important }
legend {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none
-o-user-select: none;
user-select: none;
}

View File

@ -168,6 +168,7 @@ function doveadm_authenticate($hash, $algorithm, $password) {
} }
function check_login($user, $pass) { function check_login($user, $pass) {
global $pdo; global $pdo;
global $redis;
if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) { if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) {
return false; return false;
} }
@ -229,10 +230,12 @@ function check_login($user, $pass) {
} }
if (!isset($_SESSION['ldelay'])) { if (!isset($_SESSION['ldelay'])) {
$_SESSION['ldelay'] = "0"; $_SESSION['ldelay'] = "0";
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
} }
elseif (!isset($_SESSION['mailcow_cc_username'])) { elseif (!isset($_SESSION['mailcow_cc_username'])) {
$_SESSION['ldelay'] = $_SESSION['ldelay']+0.5; $_SESSION['ldelay'] = $_SESSION['ldelay']+0.5;
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
} }
sleep($_SESSION['ldelay']); sleep($_SESSION['ldelay']);

View File

@ -47,6 +47,10 @@ jQuery(function($){
e.preventDefault(); e.preventDefault();
draw_rspamd_history(); draw_rspamd_history();
}); });
$("#import_dkim_legend").on('click', function(e) {
e.preventDefault();
$('#import_dkim_arrow').toggleClass("animation");
});
function draw_postfix_logs() { function draw_postfix_logs() {
ft_postfix_logs = FooTable.init('#postfix_log', { ft_postfix_logs = FooTable.init('#postfix_log', {
"columns": [ "columns": [

View File

@ -1,96 +0,0 @@
<?php
/* updates.php - this file is part of SOGo
*
* Copyright (C) 2006-2014 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* This script handles the automatic propagation of extensions pertaining to a
SOGo site. It requires PHP 4.1.0 or later. */
$plugin_dir = 'thunderbird-plugins';
chdir($plugin_dir);
$plugins = array();
if (file_exists('version.csv'))
{
$fh = fopen('version.csv', 'r');
if ($fh)
{
while (($row = fgetcsv($fh, 1000, ';')) !== FALSE)
{
$plugins[$row[0]] = array(
'application' => 'thunderbird',
'version' => $row[1],
'filename' => str_replace('__DOMAIN__', $_GET["domain"], $row[2]),
);
}
fclose($fh);
}
}
$applications
= array( "thunderbird" => "<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
<em:minVersion>31.0</em:minVersion>
<em:maxVersion>31.*</em:maxVersion>" );
$pluginname = $_GET["plugin"];
$plugin =& $plugins[$pluginname];
$application =& $applications[$plugin["application"]];
if ( $plugin ) {
$platform = $_GET["platform"];
if ( $platform
&& file_exists( $platform . "/" . $plugin["filename"] ) ) {
$plugin["filename"] = $platform . "/" . $plugin["filename"];
}
elseif ( !file_exists( $plugin["filename"] ) ) {
$plugin = false;
}
}
if ( $plugin ) {
header("Content-type: text/xml; charset=utf-8");
echo ('<?xml version="1.0"?>' . "\n");
?>
<!DOCTYPE RDF>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:extension:<?php echo $pluginname ?>">
<em:updates>
<Seq>
<li>
<Description>
<em:version><?php echo $plugin["version"] ?></em:version>
<em:targetApplication>
<Description>
<?php echo $applications[$plugin["application"]] ?>
<em:updateLink><?php echo 'https://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . '/' . $plugin_dir . '/' . $plugin["filename"] ?></em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
</RDF>
<?php
} else {
header("Content-type: text/plain; charset=utf-8", true, 404);
echo( 'Plugin not found' );
}
?>

View File

@ -1,5 +0,0 @@
*.zip
sogo-*-master
version.csv
*.xpi
*.tar.gz

View File

@ -1,61 +0,0 @@
#!/bin/bash
set -e
MAILHOST=$1
cd $(dirname $0)
wget -O integrator.tar.gz https://github.com/inverse-inc/sogo-integrator.tb31/archive/master.tar.gz
wget -O connector.tar.gz https://github.com/inverse-inc/sogo-connector.tb31/archive/master.tar.gz
mkdir -p integrator connector
tar --strip-components=1 -C integrator -xf integrator.tar.gz
tar --strip-components=1 -C connector -xf connector.tar.gz
# build custom integrator
while read DOMAIN; do
echo "Building SOGo Integrator for $DOMAIN hosted on $MAILHOST"
cd integrator
echo > defaults/preferences/site.js
mkdir -p custom/${DOMAIN}
cp -r custom/sogo-demo/* custom/${DOMAIN}/
sed -i "s/http:\/\/sogo-demo\.inverse\.ca/https:\/\/${MAILHOST}/g" custom/${DOMAIN}/chrome/content/extensions.rdf
sed -i "s/plugins\/updates\.php[?]/thunderbird-plugins.php?domain=${DOMAIN}\&amp;/g" custom/${DOMAIN}/chrome/content/extensions.rdf
echo 'pref("sogo-integrator.autocomplete.server.urlid", "'${DOMAIN}'");' > custom/${DOMAIN}/defaults/preferences/site.js
echo 'pref("mail.collect_email_address_outgoing", false);' >> custom/${DOMAIN}/defaults/preferences/site.js
sed -i 's/<\/Seq>/<li><Description em:id="sieve@mozdev.org" em:name="Sieve"\/><\/li><li><Description em:id="imap-acl@sirphreak.com" em:name="Imap-ACL-Extension"\/><\/li><\/Seq>/g' custom/${DOMAIN}/chrome/content/extensions.rdf
make build=${DOMAIN}
INTEGRATOR_VER=$(grep em:version install.rdf | awk -F '"' '{print $2}')
cp sogo-integrator-*-${DOMAIN}.xpi ../sogo-integrator-${INTEGRATOR_VER}-${DOMAIN}.xpi
cd ..
done
# build connector
cd connector
make
CONNECTOR_VER=$(grep em:version install.rdf | awk -F '"' '{print $2}')
cp sogo-connector-*.xpi ../sogo-connector-${CONNECTOR_VER}.xpi
cd ..
# download Sieve plugin
SIEVE_RELEASES=$(wget --header="Accept: application/vnd.github.v3+json" -qO - https://api.github.com/repos/thsmi/sieve/releases)
SIEVE_VER=$(echo "$SIEVE_RELEASES" | grep -o '"tag_name": *"[^"]*"' | head -n 1 | awk -F '"' '{print $4}')
SIEVE_URL=$(echo "$SIEVE_RELEASES" | grep -o '"browser_download_url": *"[^"]*"' | head -n 1 | awk -F '"' '{print $4}')
wget -O sieve-${SIEVE_VER}.xpi ${SIEVE_URL}
unset SIEVE_RELEASES
# download ACL plugin
IMAP_ACL_RELEASES=$(wget -qO - 'https://addons.mozilla.org/api/v3/addons/addon/176736')
IMAP_ACL_VER=$(echo "$IMAP_ACL_RELEASES" | grep -o '"version": *"[^"]*"' | head -n 1 | awk -F '"' '{print $4}')
IMAP_ACL_URL=$(echo "$IMAP_ACL_RELEASES" | grep -o '"url": *"[^"]*\.xpi' | head -n 1 | awk -F '"' '{print $4}')
wget -O imap_acl_extension-${IMAP_ACL_VER}-tb.xpi ${IMAP_ACL_URL}
unset IMAP_ACL_RELEASES
# update version file
echo "sogo-connector@inverse.ca;${CONNECTOR_VER};sogo-connector-${CONNECTOR_VER}.xpi" > version.csv
echo "sogo-integrator@inverse.ca;${INTEGRATOR_VER};sogo-integrator-${INTEGRATOR_VER}-__DOMAIN__.xpi" >> version.csv
echo "sieve@mozdev.org;${SIEVE_VER};sieve-${SIEVE_VER}.xpi" >> version.csv
echo "imap-acl@sirphreak.com;${IMAP_ACL_VER};imap_acl_extension-${IMAP_ACL_VER}-tb.xpi" >> version.csv
rm -rf connector integrator *.tar.gz

View File

@ -66,9 +66,11 @@ services:
- redis - redis
clamd-mailcow: clamd-mailcow:
image: mailcow/clamd:1.0 image: mailcow/clamd:1.1
build: ./data/Dockerfiles/clamd build: ./data/Dockerfiles/clamd
restart: always restart: always
environment:
- SKIP_CLAMD=${SKIP_CLAMD:-n}
dns: dns:
- 172.22.1.254 - 172.22.1.254
dns_search: mailcow-network dns_search: mailcow-network
@ -143,7 +145,7 @@ services:
- phpfpm - phpfpm
sogo-mailcow: sogo-mailcow:
image: mailcow/sogo:1.0 image: mailcow/sogo:1.1
build: ./data/Dockerfiles/sogo build: ./data/Dockerfiles/sogo
depends_on: depends_on:
unbound-mailcow: unbound-mailcow:
@ -156,7 +158,6 @@ services:
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
volumes: volumes:
- ./data/conf/sogo/:/etc/sogo/ - ./data/conf/sogo/:/etc/sogo/
- ./data/web/thunderbird-plugins:/thunderbird
restart: always restart: always
logging: logging:
options: options:
@ -171,7 +172,7 @@ services:
- sogo - sogo
dovecot-mailcow: dovecot-mailcow:
image: mailcow/dovecot:1.1 image: mailcow/dovecot:1.2
build: ./data/Dockerfiles/dovecot build: ./data/Dockerfiles/dovecot
depends_on: depends_on:
unbound-mailcow: unbound-mailcow:
@ -206,7 +207,7 @@ services:
- dovecot - dovecot
postfix-mailcow: postfix-mailcow:
image: mailcow/postfix:1.0 image: mailcow/postfix:1.1
build: ./data/Dockerfiles/postfix build: ./data/Dockerfiles/postfix
depends_on: depends_on:
unbound-mailcow: unbound-mailcow:
@ -293,7 +294,7 @@ services:
acme-mailcow: acme-mailcow:
depends_on: depends_on:
- nginx-mailcow - nginx-mailcow
image: mailcow/acme:1.11 image: mailcow/acme:1.12
build: ./data/Dockerfiles/acme build: ./data/Dockerfiles/acme
dns: dns:
- 172.22.1.254 - 172.22.1.254
@ -319,7 +320,7 @@ services:
- acme - acme
fail2ban-mailcow: fail2ban-mailcow:
image: mailcow/fail2ban:1.4 image: mailcow/fail2ban:1.5
build: ./data/Dockerfiles/fail2ban build: ./data/Dockerfiles/fail2ban
depends_on: depends_on:
- dovecot-mailcow - dovecot-mailcow
@ -337,8 +338,8 @@ services:
- 172.22.1.254 - 172.22.1.254
dns_search: mailcow-network dns_search: mailcow-network
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /lib/modules:/lib/modules:ro - /lib/modules:/lib/modules:ro
ipv6nat: ipv6nat:
image: robbertkl/ipv6nat image: robbertkl/ipv6nat
restart: always restart: always

View File

@ -58,7 +58,7 @@ HTTPS_BIND=0.0.0.0
# ------------------------------ # ------------------------------
# You should leave that alone # You should leave that alone
# Format: 11.22.33.44:25 or 0.0.0.0:465 etc. # Format: 11.22.33.44:25 or 0.0.0.0:465 etc.
# Do _not_ use IP:PORT in HTTPS_BIND or HTTPS_PORT # Do _not_ use IP:PORT in HTTP(S)_BIND or HTTP(S)_PORT
SMTP_PORT=25 SMTP_PORT=25
SMTPS_PORT=465 SMTPS_PORT=465
@ -87,6 +87,9 @@ SKIP_IP_CHECK=n
# To never run fail2ban-mailcow # To never run fail2ban-mailcow
SKIP_FAIL2BAN=n SKIP_FAIL2BAN=n
# To never run clamd-mailcow
SKIP_CLAMD=n
EOF EOF
mkdir -p data/assets/ssl mkdir -p data/assets/ssl

View File

@ -7,6 +7,25 @@ if [[ -z $(which git) ]]; then echo "Cannot find git, exiting."; exit 1; fi
if [[ -z $(which awk) ]]; then echo "Cannot find awk, exiting."; exit 1; fi if [[ -z $(which awk) ]]; then echo "Cannot find awk, exiting."; exit 1; fi
if [[ -z $(which sha1sum) ]]; then echo "Cannot find sha1sum, exiting."; exit 1; fi if [[ -z $(which sha1sum) ]]; then echo "Cannot find sha1sum, exiting."; exit 1; fi
CONFIG_ARRAY=("SKIP_LETS_ENCRYPT" "SKIP_CLAMD" "SKIP_IP_CHECK" "SKIP_FAIL2BAN" "ADDITIONAL_SAN")
echo >> mailcow.conf
for option in ${CONFIG_ARRAY[@]}; do
if [[ ${option} == "ADDITIONAL_SAN" ]]; then
if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo "${option}=" >> mailcow.conf
fi
elif [[ ${option} == "COMPOSE_PROJECT_NAME" ]]; then
if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo "${COMPOSE_PROJECT_NAME}=mailcow-dockerized" >> mailcow.conf
fi
elif ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo "${option}=n" >> mailcow.conf
fi
done
echo -en "Checking internet connection... " echo -en "Checking internet connection... "
curl -o /dev/null google.com -sm3 curl -o /dev/null google.com -sm3
if [[ $? != 0 ]]; then if [[ $? != 0 ]]; then
@ -106,14 +125,16 @@ chmod +x $(which docker-compose)
echo -e "\e[32mStarting mailcow...\e[0m" echo -e "\e[32mStarting mailcow...\e[0m"
sleep 2 sleep 2
docker-compose up -d --remove-orphans docker-compose up -d --remove-orphans
#echo -e "\e[32mCleaning up Docker objects...\e[0m" #echo -e "\e[32mCleaning up dangling Docker objects...\e[0m"
if docker images -f "dangling=true" | grep ago --quiet; then if [[ ! -z $(docker images -qf "dangling=true") ]]; then
docker rmi -f $(docker images -f "dangling=true" -q) docker rmi -f $(docker images -qf "dangling=true" -q)
fi
if [[ ! -z $(docker volume ls -qf dangling=true) ]]; then
docker volume rm $(docker volume ls -qf dangling=true) docker volume rm $(docker volume ls -qf dangling=true)
fi fi
echo "In case you encounter any problem, hard-reset to a state before updating mailcow:" #echo "In case you encounter any problem, hard-reset to a state before updating mailcow:"
echo #echo
git reflog --color=always | grep "Before update on " #git reflog --color=always | grep "Before update on "
echo #echo
echo "Use \"git reset --hard hash-on-the-left\" and run docker-compose up -d afterwards." #echo "Use \"git reset --hard hash-on-the-left\" and run docker-compose up -d afterwards."