From ee454755676c988a756916949ffb6677d17a2b05 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 2 Nov 2021 12:21:40 +0100 Subject: [PATCH 01/13] updated roundcube. added cleanup run at startup --- webmails/roundcube/Dockerfile | 7 ++----- webmails/roundcube/start.py | 6 ++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile index 1f788918..a290c24a 100644 --- a/webmails/roundcube/Dockerfile +++ b/webmails/roundcube/Dockerfile @@ -17,9 +17,9 @@ RUN apt-get update && apt-get install -y \ # Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube RUN pip3 install socrate -ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.4.11/roundcubemail-1.4.11-complete.tar.gz +ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.5.0/roundcubemail-1.5.0-complete.tar.gz -ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.1.2/carddav-v4.1.2.tar.gz +ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.2.2/carddav-v4.2.2.tar.gz RUN apt-get update && apt-get install -y \ zlib1g-dev libzip4 libzip-dev libpq-dev \ @@ -35,9 +35,6 @@ RUN apt-get update && apt-get install -y \ && mv carddav html/plugins/ \ && cd html \ && rm -rf CHANGELOG INSTALL LICENSE README.md UPGRADING composer.json-dist installer composer.* \ - && sed -i 's,mod_php5.c,mod_php7.c,g' .htaccess \ - && sed -i 's,^php_value.*post_max_size,#&,g' .htaccess \ - && sed -i 's,^php_value.*upload_max_filesize,#&,g' .htaccess \ && ln -sf index.php /var/www/html/sso.php \ && ln -sf /dev/stderr /var/www/html/logs/errors.log \ && chown -R root:root . \ diff --git a/webmails/roundcube/start.py b/webmails/roundcube/start.py index efaac357..64147681 100755 --- a/webmails/roundcube/start.py +++ b/webmails/roundcube/start.py @@ -53,6 +53,12 @@ try: subprocess.check_call(["/var/www/html/bin/update.sh", "--version=?", "-y"], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: quit(1) +else: + try: + print("Cleaning database") + subprocess.check_call(["/var/www/html/bin/cleandb.sh"], stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + quit(1) # Setup database permissions os.system("chown -R www-data:www-data /data") From 0fb258e1f6bbb4b3e7b3e5f0f1cd3ba251ec0881 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 2 Nov 2021 12:27:27 +0100 Subject: [PATCH 02/13] added newsfragment --- towncrier/newsfragments/2035.enhancement | 1 + 1 file changed, 1 insertion(+) create mode 100644 towncrier/newsfragments/2035.enhancement diff --git a/towncrier/newsfragments/2035.enhancement b/towncrier/newsfragments/2035.enhancement new file mode 100644 index 00000000..77ab8580 --- /dev/null +++ b/towncrier/newsfragments/2035.enhancement @@ -0,0 +1 @@ +updated roundcube to 1.5 and carddav to 4.2.2 From 920ac4cd21eb1f2e0ca7b537f6e4fa288dc1b234 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 3 Nov 2021 15:18:00 +0100 Subject: [PATCH 03/13] updated to php8. fixed login. fixed max_filesize. --- webmails/roundcube/Dockerfile | 51 ++++++++++++++++++++++------------- webmails/roundcube/mailu.php | 6 ++--- webmails/roundcube/php.ini | 1 - webmails/roundcube/start.py | 2 +- 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile index a290c24a..aa52517f 100644 --- a/webmails/roundcube/Dockerfile +++ b/webmails/roundcube/Dockerfile @@ -1,32 +1,45 @@ -# NOTE: only add file if building for arm +# NOTE: only add qemu-arm-static if building for arm ARG ARCH="" ARG QEMU=other -FROM ${ARCH}php:7.4-apache as build_arm +FROM ${ARCH}php:8.0-apache as build_arm ONBUILD COPY --from=balenalib/rpi-alpine:3.14 /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static +FROM ${ARCH}php:8.0-apache as build_other -FROM ${ARCH}php:7.4-apache as build_other FROM build_${QEMU} -#Shared layer between rainloop and roundcube -RUN apt-get update && apt-get install -y \ - python3 curl python3-pip git python3-multidict \ - && rm -rf /var/lib/apt/lists \ - && echo "ServerSignature Off\nServerName roundcube" >> /etc/apache2/apache2.conf \ - && sed -i 's,CustomLog.*combined$,\0 "'"expr=!(%{HTTP_USER_AGENT}=='health'\&\&(-R '127.0.0.1/8' || -R '::1'))"'",' /etc/apache2/sites-available/000-default.conf -# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube -RUN pip3 install socrate +RUN set -eu \ + && apt update \ + && echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections \ + && apt install -y --no-install-recommends \ + python3 curl python3-pip git python3-multidict \ + python3-jinja2 gpg tzdata \ + && pip3 install socrate \ + && echo date.timezone=UTC > /usr/local/etc/php/conf.d/timezone.ini \ + && echo "ServerSignature Off\nServerName roundcube" >> /etc/apache2/apache2.conf \ + && sed -i 's,CustomLog.*combined$,\0 "'"expr=!(%{HTTP_USER_AGENT}=='health'\&\&(-R '127.0.0.1/8' || -R '::1'))"'",' /etc/apache2/sites-available/000-default.conf \ +\ + && mark="$(apt-mark showmanual)" \ + && apt install -y --no-install-recommends \ + libfreetype6-dev libicu-dev libjpeg62-turbo-dev libldap2-dev libmagickwand-dev \ + libpng-dev libpq-dev libsqlite3-dev libzip-dev libpspell-dev libonig-dev \ + && ln -s php.ini-production /usr/local/etc/php/php.ini \ + && docker-php-ext-configure gd --with-jpeg --with-freetype \ + && docker-php-ext-install exif gd intl zip pspell pdo_mysql pdo_pgsql pdo_sqlite \ + && pecl install imagick \ + && docker-php-ext-enable imagick opcache \ + && apt-mark auto '.*' >/dev/null \ + && apt-mark manual ${mark} >/dev/null \ + && ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so | awk '/=>/ { print $3 }' | sort -u | \ + xargs -r dpkg-query -S | cut -d: -f1 | sort -u | xargs -r apt-mark manual >/dev/null \ + && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ + && rm -rf /var/lib/apt/lists ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.5.0/roundcubemail-1.5.0-complete.tar.gz ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.2.2/carddav-v4.2.2.tar.gz -RUN apt-get update && apt-get install -y \ - zlib1g-dev libzip4 libzip-dev libpq-dev \ - python3-jinja2 \ - gpg \ - && docker-php-ext-install zip pdo_mysql pdo_pgsql \ - && echo date.timezone=UTC > /usr/local/etc/php/conf.d/timezone.ini \ +RUN set -eu \ && rm -rf /var/www/html/ \ && cd /var/www \ && curl -sL ${ROUNDCUBE_URL} | tar xz \ @@ -34,13 +47,12 @@ RUN apt-get update && apt-get install -y \ && mv roundcubemail-* html \ && mv carddav html/plugins/ \ && cd html \ - && rm -rf CHANGELOG INSTALL LICENSE README.md UPGRADING composer.json-dist installer composer.* \ + && rm -rf CHANGELOG.md SECURITY.md INSTALL LICENSE README.md UPGRADING composer.json-dist installer composer.* \ && ln -sf index.php /var/www/html/sso.php \ && ln -sf /dev/stderr /var/www/html/logs/errors.log \ && chown -R root:root . \ && chown www-data:www-data logs temp \ && chmod -R a+rX . \ - && rm -rf /var/lib/apt/lists \ && a2enmod rewrite deflate expires headers COPY php.ini /php.ini @@ -54,3 +66,4 @@ VOLUME ["/data"] CMD /start.py HEALTHCHECK CMD curl -f -L -H 'User-Agent: health' http://localhost/ || exit 1 + diff --git a/webmails/roundcube/mailu.php b/webmails/roundcube/mailu.php index f5079e98..db117faa 100644 --- a/webmails/roundcube/mailu.php +++ b/webmails/roundcube/mailu.php @@ -23,9 +23,9 @@ class mailu extends rcube_plugin function authenticate($args) { - if (!in_array('HTTP_X_REMOTE_USER', $_SERVER) || !in_array('HTTP_X_REMOTE_USER_TOKEN', $_SERVER)) { - header('HTTP/1.0 403 Forbidden'); - die(); + if (!array_key_exists('HTTP_X_REMOTE_USER', $_SERVER) or !array_key_exists('HTTP_X_REMOTE_USER_TOKEN', $_SERVER)) { + header('Location: sso.php'); + exit(); } $args['user'] = $_SERVER['HTTP_X_REMOTE_USER']; $args['pass'] = $_SERVER['HTTP_X_REMOTE_USER_TOKEN']; diff --git a/webmails/roundcube/php.ini b/webmails/roundcube/php.ini index 27992231..3e77a4e5 100644 --- a/webmails/roundcube/php.ini +++ b/webmails/roundcube/php.ini @@ -1,5 +1,4 @@ expose_php=Off -date.timezone=UTC upload_max_filesize = {{ MAX_FILESIZE }}M post_max_size = {{ MAX_FILESIZE }}M diff --git a/webmails/roundcube/start.py b/webmails/roundcube/start.py index 64147681..801d028f 100755 --- a/webmails/roundcube/start.py +++ b/webmails/roundcube/start.py @@ -8,7 +8,7 @@ import subprocess log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING")) -os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT")) * 0.66 / 1048576)) +os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT")) / 0.66 / 1048576)) db_flavor = os.environ.get("ROUNDCUBE_DB_FLAVOR", "sqlite") if db_flavor == "sqlite": From c89045ed03929a61ad856ba867f1222cc8345696 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 3 Nov 2021 15:20:30 +0100 Subject: [PATCH 04/13] duh --- webmails/roundcube/start.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webmails/roundcube/start.py b/webmails/roundcube/start.py index 801d028f..64147681 100755 --- a/webmails/roundcube/start.py +++ b/webmails/roundcube/start.py @@ -8,7 +8,7 @@ import subprocess log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING")) -os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT")) / 0.66 / 1048576)) +os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT")) * 0.66 / 1048576)) db_flavor = os.environ.get("ROUNDCUBE_DB_FLAVOR", "sqlite") if db_flavor == "sqlite": From 949efcf5371efe6f2ca378402ec8bc3735454e49 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 3 Nov 2021 19:16:37 +0100 Subject: [PATCH 05/13] prevent endless redirect loop on nginx failure --- webmails/roundcube/mailu.php | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/webmails/roundcube/mailu.php b/webmails/roundcube/mailu.php index db117faa..2f2bbe41 100644 --- a/webmails/roundcube/mailu.php +++ b/webmails/roundcube/mailu.php @@ -24,9 +24,15 @@ class mailu extends rcube_plugin function authenticate($args) { if (!array_key_exists('HTTP_X_REMOTE_USER', $_SERVER) or !array_key_exists('HTTP_X_REMOTE_USER_TOKEN', $_SERVER)) { - header('Location: sso.php'); + if ($_SERVER['PHP_SELF'] == '/sso.php') { + header('HTTP/1.0 403 Forbidden'); + print('mailu sso failure'); + } else { + header('Location: sso.php'); + } exit(); } + $args['user'] = $_SERVER['HTTP_X_REMOTE_USER']; $args['pass'] = $_SERVER['HTTP_X_REMOTE_USER_TOKEN']; @@ -36,13 +42,13 @@ class mailu extends rcube_plugin return $args; } - function logout($args) { - // Redirect to global SSO logout path. + // Redirect to global SSO logout path. + function logout($args) + { $this->load_config(); - $sso_logout_url = rcmail::get_instance()->config->get('sso_logout_url'); - header("Location: " . $sso_logout_url, true); - exit; + header('Location: ' . $sso_logout_url, true); + exit(); } function login($args) @@ -50,15 +56,16 @@ class mailu extends rcube_plugin header('Location: index.php'); exit(); } + function login_failed($args) { $ua = $_SERVER['HTTP_USER_AGENT']; $ra = $_SERVER['REMOTE_ADDR']; if ($ua == 'health' and ($ra == '127.0.0.1' or $ra == '::1')) { - echo "OK"; - exit; + print('OK'); + } else { + header('Location: sso.php'); } - header('Location: sso.php'); exit(); } From c5a6799d2f89c625cc6c8afd08082feec00901c2 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 3 Nov 2021 19:17:59 +0100 Subject: [PATCH 06/13] updated newsfragment --- towncrier/newsfragments/2035.enhancement | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/towncrier/newsfragments/2035.enhancement b/towncrier/newsfragments/2035.enhancement index 77ab8580..91345cbd 100644 --- a/towncrier/newsfragments/2035.enhancement +++ b/towncrier/newsfragments/2035.enhancement @@ -1 +1 @@ -updated roundcube to 1.5 and carddav to 4.2.2 +updated roundcube to 1.5 and carddav to 4.2.2 using php8 From 6003e11533a0d1490f55cdae4df5c0152468eed1 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 3 Nov 2021 19:32:31 +0100 Subject: [PATCH 07/13] duh. add timezone (again) --- webmails/roundcube/Dockerfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile index aa52517f..b73b9e44 100644 --- a/webmails/roundcube/Dockerfile +++ b/webmails/roundcube/Dockerfile @@ -39,6 +39,8 @@ ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1 ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.2.2/carddav-v4.2.2.tar.gz +ENV TZ Etc/UTC + RUN set -eu \ && rm -rf /var/www/html/ \ && cd /var/www \ @@ -53,7 +55,8 @@ RUN set -eu \ && chown -R root:root . \ && chown www-data:www-data logs temp \ && chmod -R a+rX . \ - && a2enmod rewrite deflate expires headers + && a2enmod rewrite deflate expires headers \ + && echo date.timezone=${TZ} > /usr/local/etc/php/conf.d/timezone.ini COPY php.ini /php.ini COPY config.inc.php /var/www/html/config/ From 1ebdb26979ab48bae452795ab64f967e2d2d6f16 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 29 Nov 2021 14:21:26 +0100 Subject: [PATCH 08/13] updated to rc 1.5.1 --- webmails/roundcube/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile index 59527af8..d97c0cb7 100644 --- a/webmails/roundcube/Dockerfile +++ b/webmails/roundcube/Dockerfile @@ -37,7 +37,7 @@ RUN set -eu \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ && rm -rf /var/lib/apt/lists -ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.5.0/roundcubemail-1.5.0-complete.tar.gz +ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.5.1/roundcubemail-1.5.1-complete.tar.gz ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.2.2/carddav-v4.2.2.tar.gz From 7c2c2dc65a788d8f54d0e05a3e8fa07c4ee6c1a5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 30 Nov 2021 17:18:59 +0100 Subject: [PATCH 09/13] updated to carddav 4.3.0 --- webmails/roundcube/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile index d97c0cb7..c71aa8dd 100644 --- a/webmails/roundcube/Dockerfile +++ b/webmails/roundcube/Dockerfile @@ -39,7 +39,7 @@ RUN set -eu \ ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.5.1/roundcubemail-1.5.1-complete.tar.gz -ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.2.2/carddav-v4.2.2.tar.gz +ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.3.0/carddav-v4.3.0.tar.gz RUN set -eu \ && rm -rf /var/www/html/ \ From 547ad253e10cf966134ca8369d765e3c6901d372 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 17 Dec 2021 15:54:05 +0100 Subject: [PATCH 10/13] added plugin selection, derive key, clean env --- webmails/roundcube/Dockerfile | 7 +-- webmails/roundcube/config.inc.php | 48 +++++++-------- webmails/roundcube/healthcheck.sh | 2 + webmails/roundcube/start.py | 99 +++++++++++++++++++++---------- 4 files changed, 93 insertions(+), 63 deletions(-) create mode 100755 webmails/roundcube/healthcheck.sh diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile index c71aa8dd..bcdc7975 100644 --- a/webmails/roundcube/Dockerfile +++ b/webmails/roundcube/Dockerfile @@ -38,7 +38,6 @@ RUN set -eu \ && rm -rf /var/lib/apt/lists ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.5.1/roundcubemail-1.5.1-complete.tar.gz - ENV CARDDAV_URL https://github.com/mstilkerich/rcmcarddav/releases/download/v4.3.0/carddav-v4.3.0.tar.gz RUN set -eu \ @@ -58,10 +57,10 @@ RUN set -eu \ && a2enmod rewrite deflate expires headers \ && echo date.timezone=${TZ} > /usr/local/etc/php/conf.d/timezone.ini -COPY php.ini /php.ini -COPY config.inc.php /var/www/html/config/ COPY mailu.php /var/www/html/plugins/mailu/mailu.php -COPY start.py /start.py +COPY php.ini / +COPY config.inc.php / +COPY start.py / EXPOSE 80/tcp VOLUME ["/data"] diff --git a/webmails/roundcube/config.inc.php b/webmails/roundcube/config.inc.php index 99f147fc..67a8065d 100644 --- a/webmails/roundcube/config.inc.php +++ b/webmails/roundcube/config.inc.php @@ -3,46 +3,29 @@ $config = array(); // Generals -$config['db_dsnw'] = getenv('DB_DSNW');; +$config['db_dsnw'] = '{{ DB_DSNW }}'; $config['temp_dir'] = '/tmp/'; -$config['des_key'] = getenv('SECRET_KEY') ? getenv('SECRET_KEY') : trim(file_get_contents(getenv('SECRET_KEY_FILE'))); +$config['des_key'] = '{{ SECRET_KEY }}'; $config['cipher_method'] = 'AES-256-CBC'; $config['identities_level'] = 0; $config['reply_all_mode'] = 1; - -// List of active plugins (in plugins/ directory) -$config['plugins'] = array( - 'archive', - 'zipdownload', - 'markasjunk', - 'managesieve', - 'enigma', - 'carddav' -); - -$front = getenv('FRONT_ADDRESS') ? getenv('FRONT_ADDRESS') : 'front'; -$imap = getenv('IMAP_ADDRESS') ? getenv('IMAP_ADDRESS') : 'imap'; +$config['log_driver'] = 'stdout'; +$config['zipdownload_selection'] = true; +$config['enable_spellcheck'] = true; +$config['spellcheck_engine'] = 'pspell'; // Mail servers -$config['default_host'] = $front; +$config['default_host'] = '{{ FRONT_ADDRESS or "front" }}'; $config['default_port'] = 10143; -$config['smtp_server'] = $front; +$config['smtp_server'] = '{{ FRONT_ADDRESS or "front" }}'; $config['smtp_port'] = 10025; $config['smtp_user'] = '%u'; $config['smtp_pass'] = '%p'; // Sieve script management -$config['managesieve_host'] = $imap; +$config['managesieve_host'] = '{{ IMAP_ADDRESS or "imap" }}'; $config['managesieve_usetls'] = false; -// Customization settings -if (filter_var(getenv('ADMIN'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) { - $config['support_url'] = getenv('WEB_ADMIN') ? '../..' . getenv('WEB_ADMIN') : ''; -} -$config['product_name'] = 'Mailu Webmail'; -array_push($config['plugins'], 'mailu'); -$config['sso_logout_url'] = '/sso/logout'; - // We access the IMAP and SMTP servers locally with internal names, SSL // will obviously fail but this sounds better than allowing insecure login // from the outter world @@ -56,11 +39,22 @@ $config['imap_conn_options'] = $ssl_no_check; $config['smtp_conn_options'] = $ssl_no_check; $config['managesieve_conn_options'] = $ssl_no_check; +// roundcube customization +$config['product_name'] = 'Mailu Webmail'; +{%- if ADMIN and WEB_ADMIN %} +$config['support_url'] = '../..{{ WEB_ADMIN }}'; +{%- endif %} +$config['plugins'] = array({{ PLUGINS }}); + // skin name: folder from skins/ $config['skin'] = 'elastic'; -// Enigma gpg plugin +// configure mailu sso plugin +$config['sso_logout_url'] = '/sso/logout'; + +// configure enigma gpg plugin $config['enigma_pgp_homedir'] = '/data/gpg'; // Set From header for DKIM signed message delivery reports $config['mdn_use_from'] = true; + diff --git a/webmails/roundcube/healthcheck.sh b/webmails/roundcube/healthcheck.sh new file mode 100755 index 00000000..97ecf745 --- /dev/null +++ b/webmails/roundcube/healthcheck.sh @@ -0,0 +1,2 @@ +#!/bin/sh +SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000 2>/dev/null | grep -qFx pong diff --git a/webmails/roundcube/start.py b/webmails/roundcube/start.py index 64147681..2b217539 100755 --- a/webmails/roundcube/start.py +++ b/webmails/roundcube/start.py @@ -1,67 +1,102 @@ #!/usr/bin/python3 import os -import logging as log +import logging import sys from socrate import conf import subprocess +import hmac -log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING")) +env = os.environ -os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT")) * 0.66 / 1048576)) +logging.basicConfig(stream=sys.stderr, level=env.get("LOG_LEVEL", "WARNING")) -db_flavor = os.environ.get("ROUNDCUBE_DB_FLAVOR", "sqlite") +# jinja context +context = {} +context.update(env) + +context["MAX_FILESIZE"] = str(int(int(env.get("MESSAGE_SIZE_LIMIT", "50000000")) * 0.66 / 1048576)) + +db_flavor = env.get("ROUNDCUBE_DB_FLAVOR", "sqlite") if db_flavor == "sqlite": - os.environ["DB_DSNW"] = "sqlite:////data/roundcube.db" + context["DB_DSNW"] = "sqlite:////data/roundcube.db" elif db_flavor == "mysql": - os.environ["DB_DSNW"] = "mysql://%s:%s@%s/%s" % ( - os.environ.get("ROUNDCUBE_DB_USER", "roundcube"), - os.environ.get("ROUNDCUBE_DB_PW"), - os.environ.get("ROUNDCUBE_DB_HOST", "database"), - os.environ.get("ROUNDCUBE_DB_NAME", "roundcube") + context["DB_DSNW"] = "mysql://%s:%s@%s/%s" % ( + env.get("ROUNDCUBE_DB_USER", "roundcube"), + env.get("ROUNDCUBE_DB_PW"), + env.get("ROUNDCUBE_DB_HOST", "database"), + env.get("ROUNDCUBE_DB_NAME", "roundcube") ) elif db_flavor == "postgresql": - os.environ["DB_DSNW"] = "pgsql://%s:%s@%s/%s" % ( - os.environ.get("ROUNDCUBE_DB_USER", "roundcube"), - os.environ.get("ROUNDCUBE_DB_PW"), - os.environ.get("ROUNDCUBE_DB_HOST", "database"), - os.environ.get("ROUNDCUBE_DB_NAME", "roundcube") + context["DB_DSNW"] = "pgsql://%s:%s@%s/%s" % ( + env.get("ROUNDCUBE_DB_USER", "roundcube"), + env.get("ROUNDCUBE_DB_PW"), + env.get("ROUNDCUBE_DB_HOST", "database"), + env.get("ROUNDCUBE_DB_NAME", "roundcube") ) else: - print("Unknown ROUNDCUBE_DB_FLAVOR: %s", db_flavor) + print(f"Unknown ROUNDCUBE_DB_FLAVOR: {db_flavor}", file=sys.stderr) exit(1) -conf.jinja("/php.ini", os.environ, "/usr/local/etc/php/conf.d/roundcube.ini") +# derive roundcube secret key +secret_key = env.get("SECRET_KEY") +if not secret_key: + try: + secret_key = open(env.get("SECRET_KEY_FILE"), "r").read().strip() + except Exception as exc: + print(f"Can't read SECRET_KEY from file: {exc}", file=sys.stderr) + exit(2) -# Create dirs, setup permissions +context['SECRET_KEY'] = hmac.new(bytearray(secret_key, 'utf-8'), bytearray('ROUNDCUBE_KEY', 'utf-8'), 'sha256').hexdigest() + +# roundcube plugins +# (using "dict" because it is ordered and "set" is not) +plugins = dict((p, None) for p in env.get("ROUNCUBE_PLUGINS", "").replace(" ", "").split(",") if p and os.path.isdir(os.path.join("/var/www/plugins", p))) +if plugins: + plugins["mailu"] = None +else: + plugins = dict((k, None) for k in ["archive", "zipdownload", "markasjunk", "managesieve", "enigma", "carddav", "mailu"]) + +context["PLUGINS"] = ",".join(f"'{p}'" for p in plugins) + +# create config files +conf.jinja("/php.ini", context, "/usr/local/etc/php/conf.d/roundcube.ini") +conf.jinja("/config.inc.php", context, "/var/www/html/config/config.inc.php") + +# create dirs os.system("mkdir -p /data/gpg") +print("Initializing database") try: - print("Initializing database") result = subprocess.check_output(["/var/www/html/bin/initdb.sh", "--dir", "/var/www/html/SQL"], stderr=subprocess.STDOUT) print(result.decode()) -except subprocess.CalledProcessError as e: - if "already exists" in e.stdout.decode(): +except subprocess.CalledProcessError as exc: + err = exc.stdout.decode() + if "already exists" in err: print("Already initialzed") else: - print(e.stdout.decode()) - quit(1) + print(err) + exit(3) +print("Upgrading database") try: - print("Upgrading database") subprocess.check_call(["/var/www/html/bin/update.sh", "--version=?", "-y"], stderr=subprocess.STDOUT) -except subprocess.CalledProcessError as e: - quit(1) +except subprocess.CalledProcessError as exc: + exit(4) else: + print("Cleaning database") try: - print("Cleaning database") subprocess.check_call(["/var/www/html/bin/cleandb.sh"], stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - quit(1) + except subprocess.CalledProcessError as exc: + exit(5) -# Setup database permissions +# setup permissions os.system("chown -R www-data:www-data /data") -# Run apache -os.execv("/usr/local/bin/apache2-foreground", ["apache2-foreground"]) +# clean env +[env.pop(key, None) for key in env.keys() if key == "SECRET_KEY" or key.startswith("ROUNDCUBE_")] + +# run apache +os.execve("/usr/local/bin/apache2-foreground", ["apache2-foreground"], env) + From 64acfacc73e1cd6c0421c11ce08ad5f83bd4f5e0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 17 Dec 2021 15:55:16 +0100 Subject: [PATCH 11/13] duh. typo --- webmails/roundcube/start.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webmails/roundcube/start.py b/webmails/roundcube/start.py index 2b217539..0a1dacaf 100755 --- a/webmails/roundcube/start.py +++ b/webmails/roundcube/start.py @@ -51,7 +51,7 @@ context['SECRET_KEY'] = hmac.new(bytearray(secret_key, 'utf-8'), bytearray('ROUN # roundcube plugins # (using "dict" because it is ordered and "set" is not) -plugins = dict((p, None) for p in env.get("ROUNCUBE_PLUGINS", "").replace(" ", "").split(",") if p and os.path.isdir(os.path.join("/var/www/plugins", p))) +plugins = dict((p, None) for p in env.get("ROUNDCUBE_PLUGINS", "").replace(" ", "").split(",") if p and os.path.isdir(os.path.join("/var/www/plugins", p))) if plugins: plugins["mailu"] = None else: From b3d48cc20f02ce51938a02fcdb6bba002f18c6e6 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 18 Dec 2021 16:43:18 +0100 Subject: [PATCH 12/13] fixed health check --- webmails/roundcube/mailu.php | 37 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/webmails/roundcube/mailu.php b/webmails/roundcube/mailu.php index 2f2bbe41..0596ca9d 100644 --- a/webmails/roundcube/mailu.php +++ b/webmails/roundcube/mailu.php @@ -15,7 +15,14 @@ class mailu extends rcube_plugin function startup($args) { if (empty($_SESSION['user_id'])) { - $args['action'] = 'login'; + $args['action'] = 'login'; + } + + $ua = $_SERVER['HTTP_USER_AGENT']; + $ra = $_SERVER['REMOTE_ADDR']; + if ($ua == 'health' and ($ra == '127.0.0.1' or $ra == '::1')) { + print('OK'); + exit(); } return $args; @@ -24,13 +31,13 @@ class mailu extends rcube_plugin function authenticate($args) { if (!array_key_exists('HTTP_X_REMOTE_USER', $_SERVER) or !array_key_exists('HTTP_X_REMOTE_USER_TOKEN', $_SERVER)) { - if ($_SERVER['PHP_SELF'] == '/sso.php') { - header('HTTP/1.0 403 Forbidden'); - print('mailu sso failure'); - } else { - header('Location: sso.php'); - } - exit(); + if ($_SERVER['PHP_SELF'] == '/sso.php') { + header('HTTP/1.0 403 Forbidden'); + print('mailu sso failure'); + } else { + header('Location: sso.php'); + } + exit(); } $args['user'] = $_SERVER['HTTP_X_REMOTE_USER']; @@ -53,20 +60,14 @@ class mailu extends rcube_plugin function login($args) { - header('Location: index.php'); - exit(); + header('Location: index.php'); + exit(); } function login_failed($args) { - $ua = $_SERVER['HTTP_USER_AGENT']; - $ra = $_SERVER['REMOTE_ADDR']; - if ($ua == 'health' and ($ra == '127.0.0.1' or $ra == '::1')) { - print('OK'); - } else { - header('Location: sso.php'); - } - exit(); + header('Location: sso.php'); + exit(); } } From 1a41657f904552ec01a79206bfb7d387ed3c38d0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 18 Dec 2021 17:43:21 +0100 Subject: [PATCH 13/13] add documentation, allow overrides, clean plugins --- docs/compose/docker-compose.yml | 1 + docs/compose/traefik/docker-compose.yml | 1 + docs/configuration.rst | 49 ++++++++++++++++++++++++ setup/flavors/compose/docker-compose.yml | 1 + setup/flavors/stack/docker-compose.yml | 1 + webmails/roundcube/Dockerfile | 8 +++- webmails/roundcube/config.inc.php | 7 +++- webmails/roundcube/start.py | 3 ++ 8 files changed, 68 insertions(+), 3 deletions(-) diff --git a/docs/compose/docker-compose.yml b/docs/compose/docker-compose.yml index 42be1cb0..344ea8b2 100644 --- a/docs/compose/docker-compose.yml +++ b/docs/compose/docker-compose.yml @@ -100,6 +100,7 @@ services: env_file: .env volumes: - "$ROOT/webmail:/data" + - "$ROOT/overrides/$WEBMAIL:/overrides:ro" depends_on: - imap diff --git a/docs/compose/traefik/docker-compose.yml b/docs/compose/traefik/docker-compose.yml index f295d2f8..25f341df 100644 --- a/docs/compose/traefik/docker-compose.yml +++ b/docs/compose/traefik/docker-compose.yml @@ -128,6 +128,7 @@ services: env_file: .env volumes: - "$ROOT/webmail:/data" + - "$ROOT/overrides/$WEBMAIL:/overrides:ro" depends_on: - imap diff --git a/docs/configuration.rst b/docs/configuration.rst index f7bece71..0ca6cf8f 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -262,3 +262,52 @@ The roundcube service stores configurations in a database. - ``ROUNDCUBE_DB_PW``: the database password for roundcube service. (when not ``sqlite``) - ``ROUNDCUBE_DB_USER``: the database user for roundcube service. (when not ``sqlite``) - ``ROUNDCUBE_DB_NAME``: the database name for roundcube service. (when not ``sqlite``) + +.. _webmail_settings + +Webmail settings +---------------- + + +When using roundcube it is possible to select the plugins to be enabled by setting ``ROUNDCUBE_PLUGINS`` to +a comma separated list of plugin-names. Included plugins are: + +- acl (needs configuration) +- additional_message_headers (needs configuration) +- archive +- attachment_reminder +- carddav +- database_attachmentsi +- debug_logger +- emoticons +- enigma +- help +- hide_blockquote +- identicon +- identity_select +- jqueryui +- mailu +- managesieve +- markasjunk +- new_user_dialog +- newmail_notifier +- reconnect +- show_additional_headers (needs configuration) +- subscriptions_option +- vcard_attachments +- zipdownload + +If ``ROUNDCUBE_PLUGINS`` is not set the following plugins are enabled by default: + +- archive +- carddav +- enigma +- mailu +- managesieve +- markasjunk +- zipdownload + +To disable all plugins just set ``ROUNDCUBE_PLUGINS`` to ``mailu``. + +To configure a plugin add php files named ``*.inc`` to roundcube's :ref:`override section `. + diff --git a/setup/flavors/compose/docker-compose.yml b/setup/flavors/compose/docker-compose.yml index 18a881b8..500e99d6 100644 --- a/setup/flavors/compose/docker-compose.yml +++ b/setup/flavors/compose/docker-compose.yml @@ -147,6 +147,7 @@ services: env_file: {{ env }} volumes: - "{{ root }}/webmail:/data" + - "{{ root }}/overrides/{{ webmail_type }}:/overrides:ro" depends_on: - imap {% endif %} diff --git a/setup/flavors/stack/docker-compose.yml b/setup/flavors/stack/docker-compose.yml index 0c744d7e..99e348ea 100644 --- a/setup/flavors/stack/docker-compose.yml +++ b/setup/flavors/stack/docker-compose.yml @@ -123,6 +123,7 @@ services: env_file: {{ env }} volumes: - "{{ root }}/webmail:/data" + - "{{ root }}/overrides/{{ webmail_type }}:/overrides:ro" deploy: replicas: 1 healthcheck: diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile index e2ce7eae..7584b558 100644 --- a/webmails/roundcube/Dockerfile +++ b/webmails/roundcube/Dockerfile @@ -57,7 +57,10 @@ RUN set -eu \ && chown www-data:www-data logs temp \ && chmod -R a+rX . \ && a2enmod rewrite deflate expires headers \ - && echo date.timezone=${TZ} > /usr/local/etc/php/conf.d/timezone.ini + && echo date.timezone=${TZ} > /usr/local/etc/php/conf.d/timezone.ini \ + && rm -rf plugins/{autologon,example_addressbook,http_authentication,krb_authentication,new_user_identity,password,redundant_attachments,squirrelmail_usercopy,userinfo,virtuser_file,virtuser_query} + +# enable database_attachments (and memcache?) COPY mailu.php /var/www/html/plugins/mailu/mailu.php COPY php.ini / @@ -65,7 +68,8 @@ COPY config.inc.php / COPY start.py / EXPOSE 80/tcp -VOLUME ["/data"] +VOLUME /data +VOLUME /overrides CMD /start.py diff --git a/webmails/roundcube/config.inc.php b/webmails/roundcube/config.inc.php index 67a8065d..e5a7e3c6 100644 --- a/webmails/roundcube/config.inc.php +++ b/webmails/roundcube/config.inc.php @@ -55,6 +55,11 @@ $config['sso_logout_url'] = '/sso/logout'; // configure enigma gpg plugin $config['enigma_pgp_homedir'] = '/data/gpg'; -// Set From header for DKIM signed message delivery reports +// set From header for DKIM signed message delivery reports $config['mdn_use_from'] = true; +// includes +{%- for inc in INCLUDES %} +include('{{ inc }}'); +{%- endfor %} + diff --git a/webmails/roundcube/start.py b/webmails/roundcube/start.py index 0a1dacaf..13cbdd42 100755 --- a/webmails/roundcube/start.py +++ b/webmails/roundcube/start.py @@ -59,6 +59,9 @@ else: context["PLUGINS"] = ",".join(f"'{p}'" for p in plugins) +# add overrides +context["INCLUDES"] = sorted(inc for inc in os.listdir("/overrides") if inc.endswith(".inc")) if os.path.isdir("/overrides") else [] + # create config files conf.jinja("/php.ini", context, "/usr/local/etc/php/conf.d/roundcube.ini") conf.jinja("/config.inc.php", context, "/var/www/html/config/config.inc.php")