From 3fe1dbe88145d19227d34d85d989e0bfa9a3bfcc Mon Sep 17 00:00:00 2001 From: Kevin Falcoz <0pc0defr@gmail.com> Date: Tue, 1 Feb 2022 13:08:30 +0100 Subject: [PATCH 01/33] Add input validation for domain creation --- core/admin/mailu/ui/views/domains.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/core/admin/mailu/ui/views/domains.py b/core/admin/mailu/ui/views/domains.py index a48bb154..81c90b9b 100644 --- a/core/admin/mailu/ui/views/domains.py +++ b/core/admin/mailu/ui/views/domains.py @@ -18,18 +18,21 @@ def domain_list(): def domain_create(): form = forms.DomainForm() if form.validate_on_submit(): - conflicting_domain = models.Domain.query.get(form.name.data) - conflicting_alternative = models.Alternative.query.get(form.name.data) - conflicting_relay = models.Relay.query.get(form.name.data) - if conflicting_domain or conflicting_alternative or conflicting_relay: - flask.flash('Domain %s is already used' % form.name.data, 'error') + if validators.domain(form.name.data) is True: + conflicting_domain = models.Domain.query.get(form.name.data) + conflicting_alternative = models.Alternative.query.get(form.name.data) + conflicting_relay = models.Relay.query.get(form.name.data) + if conflicting_domain or conflicting_alternative or conflicting_relay: + flask.flash('Domain %s is already used' % form.name.data, 'error') + else: + domain = models.Domain() + form.populate_obj(domain) + models.db.session.add(domain) + models.db.session.commit() + flask.flash('Domain %s created' % domain) else: - domain = models.Domain() - form.populate_obj(domain) - models.db.session.add(domain) - models.db.session.commit() - flask.flash('Domain %s created' % domain) - return flask.redirect(flask.url_for('.domain_list')) + flask.flash('Domain %s is invalid' % form.name.data, 'error') + return flask.redirect(flask.url_for('.domain_list')) return flask.render_template('domain/create.html', form=form) From 69ce21c35302d9ff2120a7a8ee0d84d4c6fc124a Mon Sep 17 00:00:00 2001 From: Kevin Falcoz <0pc0defr@gmail.com> Date: Fri, 4 Feb 2022 15:12:04 +0100 Subject: [PATCH 02/33] Create 2210.bugfix --- towncrier/newsfragments/2210.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 towncrier/newsfragments/2210.bugfix diff --git a/towncrier/newsfragments/2210.bugfix b/towncrier/newsfragments/2210.bugfix new file mode 100644 index 00000000..32c19003 --- /dev/null +++ b/towncrier/newsfragments/2210.bugfix @@ -0,0 +1 @@ +Add input validation for domain creation From 7d801c560c0dfcb140169b411afd1630df4b690e Mon Sep 17 00:00:00 2001 From: Dimitri Huisman Date: Thu, 17 Feb 2022 12:45:35 +0000 Subject: [PATCH 03/33] Improve if statement --- core/admin/mailu/ui/views/domains.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/ui/views/domains.py b/core/admin/mailu/ui/views/domains.py index 81c90b9b..8d9d5aa4 100644 --- a/core/admin/mailu/ui/views/domains.py +++ b/core/admin/mailu/ui/views/domains.py @@ -18,7 +18,7 @@ def domain_list(): def domain_create(): form = forms.DomainForm() if form.validate_on_submit(): - if validators.domain(form.name.data) is True: + if validators.domain(form.name.data): conflicting_domain = models.Domain.query.get(form.name.data) conflicting_alternative = models.Alternative.query.get(form.name.data) conflicting_relay = models.Relay.query.get(form.name.data) From 55a601de5a5ec211340d3735346328eb2f73064b Mon Sep 17 00:00:00 2001 From: Dimitri Huisman Date: Thu, 17 Feb 2022 13:09:15 +0000 Subject: [PATCH 04/33] Add missing import for validators, improve behaviour when an error occurs. --- core/admin/mailu/ui/views/domains.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/admin/mailu/ui/views/domains.py b/core/admin/mailu/ui/views/domains.py index 8d9d5aa4..4010e2ae 100644 --- a/core/admin/mailu/ui/views/domains.py +++ b/core/admin/mailu/ui/views/domains.py @@ -2,6 +2,7 @@ from mailu import models from mailu.ui import ui, forms, access from flask import current_app as app +import validators import flask import flask_login import wtforms_components @@ -26,13 +27,13 @@ def domain_create(): flask.flash('Domain %s is already used' % form.name.data, 'error') else: domain = models.Domain() - form.populate_obj(domain) + form.populate_obj(domain) models.db.session.add(domain) models.db.session.commit() flask.flash('Domain %s created' % domain) + return flask.redirect(flask.url_for('.domain_list')) else: flask.flash('Domain %s is invalid' % form.name.data, 'error') - return flask.redirect(flask.url_for('.domain_list')) return flask.render_template('domain/create.html', form=form) From 7166e7d2b2a912fc85658527a15d2e04c31ddd98 Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 19 Feb 2022 18:37:37 +0100 Subject: [PATCH 05/33] Implement #2213: slow transports --- core/postfix/conf/main.cf | 2 +- core/postfix/conf/master.cf | 16 ++++++++++++++++ core/postfix/start.py | 7 ++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/core/postfix/conf/main.cf b/core/postfix/conf/main.cf index 444dacad..1d66bcc3 100644 --- a/core/postfix/conf/main.cf +++ b/core/postfix/conf/main.cf @@ -80,7 +80,7 @@ virtual_mailbox_maps = ${podop}mailbox # Mails are transported if required, then forwarded to Dovecot for delivery relay_domains = ${podop}transport -transport_maps = ${podop}transport +transport_maps = lmdb:/etc/postfix/transport.map, ${podop}transport virtual_transport = lmtp:inet:{{ LMTP_ADDRESS }} # Sender and recipient canonical maps, mostly for SRS diff --git a/core/postfix/conf/master.cf b/core/postfix/conf/master.cf index 15613476..bec96a30 100644 --- a/core/postfix/conf/master.cf +++ b/core/postfix/conf/master.cf @@ -15,6 +15,22 @@ outclean unix n - n - 0 cleanup -o header_checks=pcre:/etc/postfix/outclean_header_filter.cf -o nested_header_checks= +# Polite policy +polite unix - - n - - smtp + -o syslog_name=postfix-polite + -o polite_destination_concurrency_limit=3 + -o polite_destination_rate_delay=0 + -o polite_destination_recipient_limit=20 + -o polite_destination_concurrency_failed_cohort_limit=10 + +# Turtle policy +turtle unix - - n - - smtp + -o syslog_name=postfix-turtle + -o turtle_destination_concurrency_limit=1 + -o turtle_destination_rate_delay=1 + -o turtle_destination_recipient_limit=5 + -o turtle_destination_concurrency_failed_cohort_limit=10 + # Internal postfix services pickup unix n - n 60 1 pickup cleanup unix n - n - 0 cleanup diff --git a/core/postfix/start.py b/core/postfix/start.py index dc5015d7..fe93de86 100755 --- a/core/postfix/start.py +++ b/core/postfix/start.py @@ -74,9 +74,10 @@ if os.path.exists("/overrides/mta-sts-daemon.yml"): else: conf.jinja("/conf/mta-sts-daemon.yml", os.environ, "/etc/mta-sts-daemon.yml") -if not os.path.exists("/etc/postfix/tls_policy.map.lmdb"): - open("/etc/postfix/tls_policy.map", "a").close() - os.system("postmap /etc/postfix/tls_policy.map") +for policy in ['tls_policy', 'transport']: + if not os.path.exists(f'/etc/postfix/{policy}.map.lmdb'): + open(f'/etc/postfix/{policy}.map', 'a').close() + os.system(f'postmap /etc/postfix/{policy}.map') if "RELAYUSER" in os.environ: path = "/etc/postfix/sasl_passwd" From a62ebceb3d9bcae8a7669767af6e7b229a7a9e33 Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sun, 20 Feb 2022 13:29:28 +0100 Subject: [PATCH 06/33] document --- docs/faq.rst | 14 ++++++++++++++ towncrier/newsfragments/2213.feature | 1 + 2 files changed, 15 insertions(+) create mode 100644 towncrier/newsfragments/2213.feature diff --git a/docs/faq.rst b/docs/faq.rst index 626f92ad..a077e6eb 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -476,6 +476,20 @@ Any mail related connection is proxied by nginx. Therefore the SMTP Banner is al .. _`1368`: https://github.com/Mailu/Mailu/issues/1368 +My emails are getting rejected, I am being told to slow down, what can I do? +```````````````````````````````````````````````````````````````````````````` + +Some email operators insist that emails are delivered slowly. Mailu maintains two separate queues for such destinations: ``polite`` and ``turtle``. To enable them for some destination you can creating an override at ``overrides/postfix/transport.map`` as follow: + +.. code-block:: bash + + yahoo.com polite: + orange.fr turtle: + +*Issue reference:* `2213`_. + +.. _`2213`: https://github.com/Mailu/Mailu/issues/2213 + My emails are getting defered, what can I do? ````````````````````````````````````````````` diff --git a/towncrier/newsfragments/2213.feature b/towncrier/newsfragments/2213.feature new file mode 100644 index 00000000..1792cf27 --- /dev/null +++ b/towncrier/newsfragments/2213.feature @@ -0,0 +1 @@ +Create a polite and turtle delivery queue to accomodate destinations that expect emails to be sent slowly From ee34417c8c2c3dd25d7363104e36d4cf478d7bfb Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sun, 20 Feb 2022 13:31:00 +0100 Subject: [PATCH 07/33] typo --- towncrier/newsfragments/2213.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/towncrier/newsfragments/2213.feature b/towncrier/newsfragments/2213.feature index 1792cf27..bc859cb1 100644 --- a/towncrier/newsfragments/2213.feature +++ b/towncrier/newsfragments/2213.feature @@ -1 +1 @@ -Create a polite and turtle delivery queue to accomodate destinations that expect emails to be sent slowly +Create a polite and turtle delivery queue to accommodate destinations that expect emails to be sent slowly From 66b660d33101ef0b8d6665c604873462fdbd0b86 Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sun, 20 Feb 2022 13:37:49 +0100 Subject: [PATCH 08/33] clarify --- docs/faq.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/faq.rst b/docs/faq.rst index a077e6eb..dfe9b3fb 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -486,6 +486,8 @@ Some email operators insist that emails are delivered slowly. Mailu maintains tw yahoo.com polite: orange.fr turtle: +Re-starting the smtp container will be required for changes to take effect. + *Issue reference:* `2213`_. .. _`2213`: https://github.com/Mailu/Mailu/issues/2213 @@ -502,7 +504,7 @@ If delivery to a specific domain fails because their DANE records are invalid or domain.example.com may domain.example.org encrypt -The syntax and options are as described in `postfix's documentation`_. Re-creating the smtp container will be required for changes to take effect. +The syntax and options are as described in `postfix's documentation`_. Re-starting the smtp container will be required for changes to take effect. .. _`postfix's documentation`: http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps From dc819795506c13d9ee9c06aec130995ee80858cc Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 5 Mar 2022 14:33:20 +0100 Subject: [PATCH 09/33] Don't bother running the query without an address This should solve the following in admin logs: "WARNING in nginx: Invalid user 'xxxx': (builtins.ValueError) invalid email address (no "@")" --- core/admin/mailu/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py index 48b47ea5..a3f4a532 100644 --- a/core/admin/mailu/models.py +++ b/core/admin/mailu/models.py @@ -636,7 +636,7 @@ in clear-text regardless of the presence of the cache. @classmethod def get(cls, email): """ find user object for email address """ - return cls.query.get(email) + '@' in email and return cls.query.get(email) @classmethod def login(cls, email, password): From 7ce7f2096b530376af4944a98bd6edc276cd648e Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 5 Mar 2022 14:54:54 +0100 Subject: [PATCH 10/33] belt, braces and suspenders --- core/admin/mailu/internal/views/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/internal/views/auth.py b/core/admin/mailu/internal/views/auth.py index a9c1261a..f95e7c89 100644 --- a/core/admin/mailu/internal/views/auth.py +++ b/core/admin/mailu/internal/views/auth.py @@ -12,7 +12,7 @@ def nginx_authentication(): """ client_ip = flask.request.headers["Client-Ip"] headers = flask.request.headers - if headers["Auth-Port"] == '25' and headers['Auth-Method'] == 'plain': + if headers["Auth-Port"] == '25': response = flask.Response() response.headers['Auth-Status'] = 'AUTH not supported' response.headers['Auth-Error-Code'] = '502 5.5.1' From 08aa32a5df169322b6f0db0dffe8185afa37723d Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 5 Mar 2022 17:59:44 +0100 Subject: [PATCH 11/33] Revert "Don't bother running the query without an address" This reverts commit dc819795506c13d9ee9c06aec130995ee80858cc. --- core/admin/mailu/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py index a3f4a532..48b47ea5 100644 --- a/core/admin/mailu/models.py +++ b/core/admin/mailu/models.py @@ -636,7 +636,7 @@ in clear-text regardless of the presence of the cache. @classmethod def get(cls, email): """ find user object for email address """ - '@' in email and return cls.query.get(email) + return cls.query.get(email) @classmethod def login(cls, email, password): From 8cf76afbabe9bf791fcca9e91ae57049b2a92c9d Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 5 Mar 2022 18:01:30 +0100 Subject: [PATCH 12/33] Catch the ValueError instead --- core/admin/mailu/internal/nginx.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py index 54eb3eb6..02998fed 100644 --- a/core/admin/mailu/internal/nginx.py +++ b/core/admin/mailu/internal/nginx.py @@ -95,6 +95,8 @@ def handle_authentication(headers): try: user = models.User.query.get(user_email) is_valid_user = True + except ValueError: + pass except sqlalchemy.exc.StatementError as exc: exc = str(exc).split('\n', 1)[0] app.logger.warn(f'Invalid user {user_email!r}: {exc}') From 91de20c49c1b0c25429a595656fab82dd10d78f9 Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 5 Mar 2022 18:22:58 +0100 Subject: [PATCH 13/33] Fix exception in logs This was occuring when you had square brackets in the domain part --- core/admin/mailu/internal/views/postfix.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/admin/mailu/internal/views/postfix.py b/core/admin/mailu/internal/views/postfix.py index ed951943..909b776e 100644 --- a/core/admin/mailu/internal/views/postfix.py +++ b/core/admin/mailu/internal/views/postfix.py @@ -5,6 +5,7 @@ from flask import current_app as app import flask import idna import re +import sqlalchemy.exc import srslib @internal.route("/postfix/dane/") @@ -158,11 +159,13 @@ def postfix_sender_rate(sender): def postfix_sender_access(sender): """ Simply reject any sender that pretends to be from a local domain """ - if not is_void_address(sender): - localpart, domain_name = models.Email.resolve_domain(sender) - return flask.jsonify("REJECT") if models.Domain.query.get(domain_name) else flask.abort(404) - else: - return flask.abort(404) + try: + if not is_void_address(sender): + localpart, domain_name = models.Email.resolve_domain(sender) + return flask.jsonify("REJECT") if models.Domain.query.get(domain_name) else flask.abort(404) + except sqlalchemy.exc.StatementError: + pass + return flask.abort(404) def is_void_address(email): From 7b9c4e01f7bea51e9f0d02da1a501b8760aeb57a Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 5 Mar 2022 18:36:27 +0100 Subject: [PATCH 14/33] improve --- core/admin/mailu/internal/nginx.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py index 02998fed..03142e62 100644 --- a/core/admin/mailu/internal/nginx.py +++ b/core/admin/mailu/internal/nginx.py @@ -93,10 +93,9 @@ def handle_authentication(headers): app.logger.warn(f'Received undecodable user/password from nginx: {raw_user_email!r}/{raw_password!r}') else: try: - user = models.User.query.get(user_email) - is_valid_user = True - except ValueError: - pass + if '@' in user_email: + user = models.User.query.get(user_email) + is_valid_user = True except sqlalchemy.exc.StatementError as exc: exc = str(exc).split('\n', 1)[0] app.logger.warn(f'Invalid user {user_email!r}: {exc}') From f01d8cd9b9b77cfb41b11db40c5f7e9898f6a45c Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 5 Mar 2022 18:41:06 +0100 Subject: [PATCH 15/33] improve --- core/admin/mailu/internal/nginx.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py index 03142e62..40d72505 100644 --- a/core/admin/mailu/internal/nginx.py +++ b/core/admin/mailu/internal/nginx.py @@ -93,9 +93,8 @@ def handle_authentication(headers): app.logger.warn(f'Received undecodable user/password from nginx: {raw_user_email!r}/{raw_password!r}') else: try: - if '@' in user_email: - user = models.User.query.get(user_email) - is_valid_user = True + user = models.User.query.get(user_email) if '@' in user_email else None + is_valid_user = bool(user) except sqlalchemy.exc.StatementError as exc: exc = str(exc).split('\n', 1)[0] app.logger.warn(f'Invalid user {user_email!r}: {exc}') From d723326b8eb66e12aaa072ca9fd9b494ec211cb0 Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Mon, 7 Mar 2022 09:04:40 +0100 Subject: [PATCH 16/33] style --- core/admin/mailu/internal/nginx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py index 40d72505..b7e246af 100644 --- a/core/admin/mailu/internal/nginx.py +++ b/core/admin/mailu/internal/nginx.py @@ -94,7 +94,7 @@ def handle_authentication(headers): else: try: user = models.User.query.get(user_email) if '@' in user_email else None - is_valid_user = bool(user) + is_valid_user = user is not None except sqlalchemy.exc.StatementError as exc: exc = str(exc).split('\n', 1)[0] app.logger.warn(f'Invalid user {user_email!r}: {exc}') From cd3eee4c51855de4de2033b0b0a45dfe035c0f50 Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Mon, 7 Mar 2022 09:09:36 +0100 Subject: [PATCH 17/33] ghostwheel42's suggestion --- core/admin/mailu/internal/views/postfix.py | 23 ++++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/core/admin/mailu/internal/views/postfix.py b/core/admin/mailu/internal/views/postfix.py index 909b776e..591dbaf3 100644 --- a/core/admin/mailu/internal/views/postfix.py +++ b/core/admin/mailu/internal/views/postfix.py @@ -159,20 +159,13 @@ def postfix_sender_rate(sender): def postfix_sender_access(sender): """ Simply reject any sender that pretends to be from a local domain """ - try: - if not is_void_address(sender): + if '@' in email: + if email.startswith('<') and email.endswith('>'): + email = email[1:-1] + try: localpart, domain_name = models.Email.resolve_domain(sender) - return flask.jsonify("REJECT") if models.Domain.query.get(domain_name) else flask.abort(404) - except sqlalchemy.exc.StatementError: - pass + if models.Domain.query.get(domain_name): + return flask.jsonify("REJECT") + except sqlalchemy.exc.StatementError: + pass return flask.abort(404) - - -def is_void_address(email): - '''True if the email is void (null) email address. - ''' - if email.startswith('<') and email.endswith('>'): - email = email[1:-1] - # Some MTAs use things like '' instead of '<>'; so let's - # consider void any such thing. - return '@' not in email From 0bfbb3bcd48325da8f07198700e42e6ebbfd4d86 Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Tue, 8 Mar 2022 13:10:27 +0100 Subject: [PATCH 18/33] doh --- core/admin/mailu/internal/views/postfix.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/admin/mailu/internal/views/postfix.py b/core/admin/mailu/internal/views/postfix.py index 591dbaf3..3482b290 100644 --- a/core/admin/mailu/internal/views/postfix.py +++ b/core/admin/mailu/internal/views/postfix.py @@ -159,9 +159,9 @@ def postfix_sender_rate(sender): def postfix_sender_access(sender): """ Simply reject any sender that pretends to be from a local domain """ - if '@' in email: - if email.startswith('<') and email.endswith('>'): - email = email[1:-1] + if '@' in sender: + if sender.startswith('<') and sender.endswith('>'): + sender = sender[1:-1] try: localpart, domain_name = models.Email.resolve_domain(sender) if models.Domain.query.get(domain_name): From a4ed46417055a36a52d3e6fdd18c64f5435b7f33 Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Wed, 9 Mar 2022 19:28:33 +0100 Subject: [PATCH 19/33] doh --- core/admin/mailu/internal/views/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/internal/views/auth.py b/core/admin/mailu/internal/views/auth.py index a9c1261a..ab259864 100644 --- a/core/admin/mailu/internal/views/auth.py +++ b/core/admin/mailu/internal/views/auth.py @@ -12,7 +12,7 @@ def nginx_authentication(): """ client_ip = flask.request.headers["Client-Ip"] headers = flask.request.headers - if headers["Auth-Port"] == '25' and headers['Auth-Method'] == 'plain': + if headers["Auth-Port"] == '25' and headers['Auth-Method'] != 'none': response = flask.Response() response.headers['Auth-Status'] = 'AUTH not supported' response.headers['Auth-Error-Code'] = '502 5.5.1' From a3c01a2bbf3fcda8cc741a79b12ff371a33b42ab Mon Sep 17 00:00:00 2001 From: the-djmaze <3752035+the-djmaze@users.noreply.github.com> Date: Fri, 11 Mar 2022 12:26:13 +0100 Subject: [PATCH 20/33] Update application.ini `contacts_autosave` is part of `[defaults]`, not `[plugins]` --- webmails/rainloop/defaults/application.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webmails/rainloop/defaults/application.ini b/webmails/rainloop/defaults/application.ini index d67ec9f0..6a024f96 100644 --- a/webmails/rainloop/defaults/application.ini +++ b/webmails/rainloop/defaults/application.ini @@ -15,5 +15,5 @@ custom_logout_link='/sso/logout' enable = On allow_sync = On -[plugins] +[defaults] contacts_autosave = On From d02296c3bc213d2c1e4a71f61cd135d757358094 Mon Sep 17 00:00:00 2001 From: Will Date: Thu, 17 Mar 2022 10:40:42 +0000 Subject: [PATCH 21/33] Update alpine-linux to 3.14.4 - OpenSSL security FIX --- core/admin/Dockerfile | 2 +- core/dovecot/Dockerfile | 2 +- core/nginx/Dockerfile | 2 +- core/none/Dockerfile | 2 +- core/postfix/Dockerfile | 2 +- optional/clamav/Dockerfile | 2 +- optional/fetchmail/Dockerfile | 2 +- optional/radicale/Dockerfile | 2 +- optional/unbound/Dockerfile | 2 +- setup/Dockerfile | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/admin/Dockerfile b/core/admin/Dockerfile index 4267f3b1..3dcdd944 100644 --- a/core/admin/Dockerfile +++ b/core/admin/Dockerfile @@ -1,5 +1,5 @@ # First stage to build assets -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 ARG ARCH="" FROM ${ARCH}node:16 as assets diff --git a/core/dovecot/Dockerfile b/core/dovecot/Dockerfile index 4663d351..7ba2baf2 100644 --- a/core/dovecot/Dockerfile +++ b/core/dovecot/Dockerfile @@ -1,4 +1,4 @@ -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 FROM $DISTRO ARG VERSION diff --git a/core/nginx/Dockerfile b/core/nginx/Dockerfile index 434f72eb..eb8180f0 100644 --- a/core/nginx/Dockerfile +++ b/core/nginx/Dockerfile @@ -1,4 +1,4 @@ -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 FROM $DISTRO ARG VERSION diff --git a/core/none/Dockerfile b/core/none/Dockerfile index df5833ce..c22c3bf6 100644 --- a/core/none/Dockerfile +++ b/core/none/Dockerfile @@ -1,6 +1,6 @@ # This is an idle image to dynamically replace any component if disabled. -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 FROM $DISTRO CMD sleep 1000000d diff --git a/core/postfix/Dockerfile b/core/postfix/Dockerfile index 6f2519db..a9b8df1a 100644 --- a/core/postfix/Dockerfile +++ b/core/postfix/Dockerfile @@ -1,4 +1,4 @@ -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 FROM $DISTRO ARG VERSION diff --git a/optional/clamav/Dockerfile b/optional/clamav/Dockerfile index 477cf89d..53a4b198 100644 --- a/optional/clamav/Dockerfile +++ b/optional/clamav/Dockerfile @@ -1,4 +1,4 @@ -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 FROM $DISTRO ARG VERSION diff --git a/optional/fetchmail/Dockerfile b/optional/fetchmail/Dockerfile index 37379521..fe582088 100644 --- a/optional/fetchmail/Dockerfile +++ b/optional/fetchmail/Dockerfile @@ -1,4 +1,4 @@ -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 FROM $DISTRO ARG VERSION diff --git a/optional/radicale/Dockerfile b/optional/radicale/Dockerfile index 10d10ea0..b31439ef 100644 --- a/optional/radicale/Dockerfile +++ b/optional/radicale/Dockerfile @@ -1,4 +1,4 @@ -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 FROM $DISTRO ARG VERSION diff --git a/optional/unbound/Dockerfile b/optional/unbound/Dockerfile index 21ba9571..5a6bc38a 100644 --- a/optional/unbound/Dockerfile +++ b/optional/unbound/Dockerfile @@ -1,4 +1,4 @@ -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 FROM $DISTRO ARG VERSION diff --git a/setup/Dockerfile b/setup/Dockerfile index cc5f0fd3..4a0f355b 100644 --- a/setup/Dockerfile +++ b/setup/Dockerfile @@ -1,4 +1,4 @@ -ARG DISTRO=alpine:3.14.3 +ARG DISTRO=alpine:3.14.4 FROM $DISTRO ARG VERSION ENV TZ Etc/UTC From c6ad3c7f9e3c4e828d8ad9154514899e5ca00d91 Mon Sep 17 00:00:00 2001 From: willofr Date: Thu, 17 Mar 2022 11:57:10 +0100 Subject: [PATCH 22/33] Create 2281.bugfix --- towncrier/newsfragments/2281.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 towncrier/newsfragments/2281.bugfix diff --git a/towncrier/newsfragments/2281.bugfix b/towncrier/newsfragments/2281.bugfix new file mode 100644 index 00000000..5163805b --- /dev/null +++ b/towncrier/newsfragments/2281.bugfix @@ -0,0 +1 @@ +Update to Alpine Linux 3.14.4 which contains a security fix for openssl. From 8775dc5b155d7ad97672f1eb5b47a9dd01031211 Mon Sep 17 00:00:00 2001 From: Maximilian Fischer Date: Thu, 17 Mar 2022 20:36:23 +0100 Subject: [PATCH 23/33] Fixing AUTH_RATELIMIT_IP not working on imap/pop3/smtp #2283 --- core/admin/mailu/internal/views/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/internal/views/auth.py b/core/admin/mailu/internal/views/auth.py index ab259864..0dbc8dc9 100644 --- a/core/admin/mailu/internal/views/auth.py +++ b/core/admin/mailu/internal/views/auth.py @@ -32,7 +32,7 @@ def nginx_authentication(): for key, value in headers.items(): response.headers[key] = str(value) is_valid_user = False - if response.headers.get("Auth-User-Exists"): + if response.headers.get("Auth-User-Exists")=="True": username = response.headers["Auth-User"] if utils.limiter.should_rate_limit_user(username, client_ip): # FIXME could be done before handle_authentication() From dcfe0fbe91a5b48d0143ee41229de7d0d9a7dcf5 Mon Sep 17 00:00:00 2001 From: Maximilian Fischer Date: Thu, 17 Mar 2022 20:40:08 +0100 Subject: [PATCH 24/33] Create 2284.bugfix --- towncrier/newsfragments/2284.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 towncrier/newsfragments/2284.bugfix diff --git a/towncrier/newsfragments/2284.bugfix b/towncrier/newsfragments/2284.bugfix new file mode 100644 index 00000000..d264db89 --- /dev/null +++ b/towncrier/newsfragments/2284.bugfix @@ -0,0 +1 @@ +Fixed AUTH_RATELIMIT_IP not working on imap/pop3/smtp. \ No newline at end of file From 630a4e9b5e18d301c83f8e49de366656c44d0857 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 Mar 2022 20:05:16 +0100 Subject: [PATCH 25/33] Update auth.py Add spaces --- core/admin/mailu/internal/views/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/internal/views/auth.py b/core/admin/mailu/internal/views/auth.py index 0dbc8dc9..426c0c49 100644 --- a/core/admin/mailu/internal/views/auth.py +++ b/core/admin/mailu/internal/views/auth.py @@ -32,7 +32,7 @@ def nginx_authentication(): for key, value in headers.items(): response.headers[key] = str(value) is_valid_user = False - if response.headers.get("Auth-User-Exists")=="True": + if response.headers.get("Auth-User-Exists") == "True": username = response.headers["Auth-User"] if utils.limiter.should_rate_limit_user(username, client_ip): # FIXME could be done before handle_authentication() From 64ad6931e993b5867ea5eec38d4ecd554d101a74 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 Mar 2022 20:08:16 +0100 Subject: [PATCH 26/33] Move 'is_valid_user = user is not None' into else --- core/admin/mailu/internal/nginx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py index b7e246af..2ee6d9b3 100644 --- a/core/admin/mailu/internal/nginx.py +++ b/core/admin/mailu/internal/nginx.py @@ -94,11 +94,11 @@ def handle_authentication(headers): else: try: user = models.User.query.get(user_email) if '@' in user_email else None - is_valid_user = user is not None except sqlalchemy.exc.StatementError as exc: exc = str(exc).split('\n', 1)[0] app.logger.warn(f'Invalid user {user_email!r}: {exc}') else: + is_valid_user = user is not None ip = urllib.parse.unquote(headers["Client-Ip"]) if check_credentials(user, password, ip, protocol, headers["Auth-Port"]): server, port = get_server(headers["Auth-Protocol"], True) From d70596d43173a60aed74ef7124a8799ad22ff9a0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 Mar 2022 20:53:46 +0100 Subject: [PATCH 27/33] Update names of language json files --- core/admin/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/admin/Dockerfile b/core/admin/Dockerfile index 4267f3b1..ca7cee43 100644 --- a/core/admin/Dockerfile +++ b/core/admin/Dockerfile @@ -13,7 +13,7 @@ COPY webpack.config.js ./ COPY assets ./assets RUN set -eu \ && sed -i 's/#007bff/#55a5d9/' node_modules/admin-lte/build/scss/_bootstrap-variables.scss \ - && for l in ca da de:de_de en:en-gb es:es_es eu fr:fr_fr he hu is it:it_it ja nb_NO:no_nb nl:nl_nl pl pt:pt_pt ru sv:sv_se zh; do \ + && for l in ca da de:de-DE en:en-GB es:es-ES eu fr:fr-FR he hu is it:it-IT ja nb_NO:no-NB nl:nl-NL pl pt:pt-PT ru sv:sv-SE zh; do \ cp node_modules/datatables.net-plugins/i18n/${l#*:}.json assets/${l%:*}.json; \ done \ && node_modules/.bin/webpack-cli --color @@ -59,4 +59,4 @@ ENV FLASK_APP mailu CMD /start.py HEALTHCHECK CMD curl -f -L http://localhost/sso/login?next=ui.index || exit 1 -RUN echo $VERSION >> /version \ No newline at end of file +RUN echo $VERSION >> /version From 77ad6d19ae7420e2ecf22caf5fcff763538e8273 Mon Sep 17 00:00:00 2001 From: DAHPr0gram3r Date: Thu, 17 Mar 2022 18:26:15 +0000 Subject: [PATCH 28/33] Fix typo in Traefik reverse proxy docs Slight typo in the Traefik reverse proxy docs. Found through running into the issue on my own instance. --- docs/reverse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reverse.rst b/docs/reverse.rst index 8d0dcc8e..91c6f67e 100644 --- a/docs/reverse.rst +++ b/docs/reverse.rst @@ -189,7 +189,7 @@ Mailu must also be configured with the information what header is used by the re .. code-block:: docker #mailu.env file - REAL_IP_HEADER=X-Real-IP + REAL_IP_HEADER=X-Real-Ip REAL_IP_FROM=x.x.x.x,y.y.y.y.y #x.x.x.x,y.y.y.y.y is the static IP address your reverse proxy uses for connecting to Mailu. From 90d7c438726784b8cc0bd9e65e09bb2809558677 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 Mar 2022 21:46:49 +0100 Subject: [PATCH 29/33] Update alpine version in rpi docs --- docs/rpi_build.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rpi_build.rst b/docs/rpi_build.rst index 5796e188..07be77de 100644 --- a/docs/rpi_build.rst +++ b/docs/rpi_build.rst @@ -17,8 +17,8 @@ Adjustments ``build_arm.sh`` uses some variables passed as ``build-arg`` to docker-compose: - ``ALPINE_VER``: version of ALPINE to use -- ``DISTRO``: is the main distro used. Dockerfiles are set on Alpine 3.10, and - build script overrides for ``balenalib/rpi-alpine:3.10`` +- ``DISTRO``: is the main distro used. Dockerfiles are set on Alpine 3.14, and + build script overrides for ``balenalib/rpi-alpine:3.14`` - ``QEMU``: Used by webmails dockerfiles. It will add ``qemu-arm-static`` only if ``QEMU`` is set to ``arm`` - ``ARCH``: Architecture to use for ``admin``, and ``webmails`` as their images From 2f75625140295369661871ca67bd333be5c7ca48 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 Mar 2022 22:49:47 +0100 Subject: [PATCH 30/33] Fix typo in docs: cert not certs --- docs/faq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq.rst b/docs/faq.rst index 9bbd359c..4757e6a1 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -527,7 +527,7 @@ These issues are typically caused by four scenarios: #. Certificates expired; #. When ``TLS_FLAVOR=letsencrypt``, it might be that the *certbot* script is not capable of obtaining the certificates for your domain. See `letsencrypt issues`_ -#. When ``TLS_FLAVOR=certs``, certificates are supposed to be copied to ``/mailu/certs``. +#. When ``TLS_FLAVOR=cert``, certificates are supposed to be copied to ``/mailu/certs``. Using an external ``letsencrypt`` program, it tends to happen people copy the whole ``letsencrypt/live`` directory containing symlinks. Symlinks do not resolve inside the container and therefore it breaks the TLS implementation. From 9b952da6c2ab1dbee2165697fb16979fc168a6af Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sun, 20 Mar 2022 12:11:50 +0100 Subject: [PATCH 31/33] Allow nginx to lookup IPv6 addresses It creates issues with RSPAMD/HFILTER_HOSTNAME_UNKNOWN on v6 enabled setups see https://github.com/Mailu/Mailu/issues/2260#issuecomment-1066797661 --- core/nginx/conf/nginx.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/nginx/conf/nginx.conf b/core/nginx/conf/nginx.conf index b9bb20b7..11b7468c 100644 --- a/core/nginx/conf/nginx.conf +++ b/core/nginx/conf/nginx.conf @@ -17,7 +17,7 @@ http { keepalive_timeout 65; server_tokens off; absolute_redirect off; - resolver {{ RESOLVER }} ipv6=off valid=30s; + resolver {{ RESOLVER }} valid=30s; {% if REAL_IP_HEADER %} real_ip_header {{ REAL_IP_HEADER }}; @@ -254,7 +254,7 @@ mail { server_name {{ HOSTNAMES.split(",")[0] }}; auth_http http://127.0.0.1:8000/auth/email; proxy_pass_error_message on; - resolver {{ RESOLVER }} ipv6=off valid=30s; + resolver {{ RESOLVER }} valid=30s; error_log /dev/stderr info; {% if TLS and not TLS_ERROR %} From a88424d19f65d03d9e62140cfdc719d95ddfee5b Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sun, 20 Mar 2022 12:16:04 +0100 Subject: [PATCH 32/33] Sturdy up the warning about v6 in setup --- setup/templates/steps/compose/03_expose.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/templates/steps/compose/03_expose.html b/setup/templates/steps/compose/03_expose.html index fe0802fb..6d2150b6 100644 --- a/setup/templates/steps/compose/03_expose.html +++ b/setup/templates/steps/compose/03_expose.html @@ -31,7 +31,7 @@ avoid generic all-interfaces addresses like 0.0.0.0 or ::