From dc819795506c13d9ee9c06aec130995ee80858cc Mon Sep 17 00:00:00 2001 From: Florent Daigniere Date: Sat, 5 Mar 2022 14:33:20 +0100 Subject: [PATCH 01/10] 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 02/10] 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 03/10] 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 04/10] 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 05/10] 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 06/10] 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 07/10] 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 08/10] 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 09/10] 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 10/10] 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):