diff --git a/core/admin/mailu/ui/views/users.py b/core/admin/mailu/ui/views/users.py
index 7f7e0ab3..eef0457c 100644
--- a/core/admin/mailu/ui/views/users.py
+++ b/core/admin/mailu/ui/views/users.py
@@ -99,18 +99,13 @@ def user_settings(user_email):
flask.url_for('.user_list', domain_name=user.domain.name))
return flask.render_template('user/settings.html', form=form, user=user)
-
-@ui.route('/user/password', methods=['GET', 'POST'], defaults={'user_email': None})
-@ui.route('/user/password/', methods=['GET', 'POST'])
-@access.owner(models.User, 'user_email')
-def user_password(user_email):
+def _process_password_change(form, user_email):
user_email_or_current = user_email or flask_login.current_user.email
user = models.User.query.get(user_email_or_current) or flask.abort(404)
- form = forms.UserPasswordForm()
if form.validate_on_submit():
if form.pw.data != form.pw2.data:
flask.flash('Passwords do not match', 'error')
- else:
+ elif user_email or models.User.login(user_email_or_current, form.current_pw.data):
if msg := utils.isBadOrPwned(form):
flask.flash(msg, "error")
return flask.render_template('user/password.html', form=form, user=user)
@@ -121,8 +116,19 @@ def user_password(user_email):
if user_email:
return flask.redirect(flask.url_for('.user_list',
domain_name=user.domain.name))
+ else:
+ flask.flash('Wrong current password', 'error')
return flask.render_template('user/password.html', form=form, user=user)
+@ui.route('/user/password', methods=['GET', 'POST'], defaults={'user_email': None})
+@access.owner(models.User, 'user_email')
+def user_password_change(user_email):
+ return _process_password_change(forms.UserPasswordChangeForm(), user_email)
+
+@ui.route('/user/password/', methods=['GET', 'POST'])
+@access.domain_admin(models.User, 'user_email')
+def user_password(user_email):
+ return _process_password_change(forms.UserPasswordForm(), user_email)
@ui.route('/user/reply', methods=['GET', 'POST'], defaults={'user_email': None})
@ui.route('/user/reply/', methods=['GET', 'POST'])
diff --git a/docs/compose/.env b/docs/compose/.env
index e5e1edbf..10bf03eb 100644
--- a/docs/compose/.env
+++ b/docs/compose/.env
@@ -135,12 +135,6 @@ WEBSITE=https://mailu.io
# Advanced settings
###################################
-# Log driver for front service. Possible values:
-# json-file (default)
-# journald (On systemd platforms, useful for Fail2Ban integration)
-# syslog (Non systemd platforms, Fail2Ban integration. Disables `docker compose log` for front!)
-LOG_DRIVER=json-file
-
# Docker-compose project name, this will prepended to containers names.
COMPOSE_PROJECT_NAME=mailu
diff --git a/docs/compose/docker-compose.yml b/docs/compose/docker-compose.yml
index 344ea8b2..3b964449 100644
--- a/docs/compose/docker-compose.yml
+++ b/docs/compose/docker-compose.yml
@@ -9,7 +9,9 @@ services:
restart: always
env_file: .env
logging:
- driver: $LOG_DRIVER
+ driver: journald
+ options:
+ tag: mailu-front
ports:
- "$BIND_ADDRESS4:80:80"
- "$BIND_ADDRESS4:443:443"
@@ -43,6 +45,10 @@ services:
image: mailu/dovecot:$VERSION
restart: always
env_file: .env
+ logging:
+ driver: journald
+ options:
+ tag: mailu-imap
volumes:
- "$ROOT/mail:/mail"
- "$ROOT/overrides/dovecot:/overrides:ro"
@@ -53,6 +59,10 @@ services:
image: mailu/postfix:$VERSION
restart: always
env_file: .env
+ logging:
+ driver: journald
+ options:
+ tag: mailu-smtp
volumes:
- "$ROOT/mailqueue:/queue"
- "$ROOT/overrides/postfix:/overrides:ro"
@@ -63,6 +73,10 @@ services:
image: mailu/rspamd:$VERSION
restart: always
env_file: .env
+ logging:
+ driver: journald
+ options:
+ tag: mailu-antispam
volumes:
- "$ROOT/filter:/var/lib/rspamd"
- "$ROOT/dkim:/dkim:ro"
@@ -88,6 +102,10 @@ services:
image: mailu/admin:$VERSION
restart: always
env_file: .env
+ logging:
+ driver: journald
+ options:
+ tag: mailu-admin
volumes:
- "$ROOT/data:/data"
- "$ROOT/dkim:/dkim"
diff --git a/docs/compose/traefik/docker-compose.yml b/docs/compose/traefik/docker-compose.yml
index 25f341df..37e89827 100644
--- a/docs/compose/traefik/docker-compose.yml
+++ b/docs/compose/traefik/docker-compose.yml
@@ -35,8 +35,6 @@ services:
image: mailu/nginx:$VERSION
restart: always
env_file: .env
- logging:
- driver: $LOG_DRIVER
labels: # Traefik labels for simple reverse-proxying
- "traefik.enable=true"
- "traefik.port=80"
diff --git a/docs/configuration.rst b/docs/configuration.rst
index 0856d9ff..952469cd 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -47,10 +47,11 @@ accounts for a specific IP subnet as defined in
``AUTH_RATELIMIT_IP_V4_MASK`` (default: /24) and
``AUTH_RATELIMIT_IP_V6_MASK`` (default: /48).
-The ``AUTH_RATELIMIT_USER`` (default: 100/day) holds a security setting for fighting
+The ``AUTH_RATELIMIT_USER`` (default: 50/day) holds a security setting for fighting
attackers that attempt to guess a user's password (typically using a password
-bruteforce attack). The value defines the limit of authentication attempts allowed
-for any given account within a specific timeframe.
+bruteforce attack). The value defines the limit of distinct authentication attempts
+allowed for any given account within a specific timeframe. Multiple attempts for the
+same account with the same password only counts for one.
The ``AUTH_RATELIMIT_EXEMPTION_LENGTH`` (default: 86400) is the number of seconds
after a successful login for which a specific IP address is exempted from rate limits.
diff --git a/docs/faq.rst b/docs/faq.rst
index c7d9e3dc..4c9ea348 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -579,8 +579,7 @@ down brute force attacks. The same applies to login attempts via the single sign
We *do* provide a possibility to export the logs from the ``front`` service and ``Admin`` service to the host.
The ``front`` container logs failed logon attempts on SMTP, IMAP and POP3.
The ``Admin`` container logs failed logon attempt on the single sign on page.
-For this you need to set ``LOG_DRIVER=journald`` or ``syslog``, depending on the log
-manager of the host. You will need to setup the proper Regex in the Fail2Ban configuration.
+You will need to setup the proper Regex in the Fail2Ban configuration.
Below an example how to do so.
If you use a reverse proxy in front of Mailu, it is vital to set the environment variables REAL_IP_HEADER and REAL_IP_FROM.
diff --git a/setup/flavors/compose/docker-compose.yml b/setup/flavors/compose/docker-compose.yml
index 7d39b929..c83ff29e 100644
--- a/setup/flavors/compose/docker-compose.yml
+++ b/setup/flavors/compose/docker-compose.yml
@@ -26,7 +26,9 @@ services:
restart: always
env_file: {{ env }}
logging:
- driver: {{ log_driver or 'json-file' }}
+ driver: journald
+ options:
+ tag: mailu-front
ports:
{% for port in (80, 443, 25, 465, 587, 110, 995, 143, 993) %}
{% if bind4 %}
@@ -38,8 +40,12 @@ services:
{% endfor %}
networks:
- default
+{% if webmail_type != 'none' %}
- webmail
+{% endif %}
+{% if webdav_enabled %}
- radicale
+{% endif %}
volumes:
- "{{ root }}/certs:/certs"
- "{{ root }}/overrides/nginx:/overrides:ro"
@@ -62,6 +68,10 @@ services:
image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}admin:${MAILU_VERSION:-{{ version }}}
restart: always
env_file: {{ env }}
+ logging:
+ driver: journald
+ options:
+ tag: mailu-admin
{% if not admin_enabled %}
ports:
- 127.0.0.1:8080:80
@@ -81,6 +91,10 @@ services:
image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}dovecot:${MAILU_VERSION:-{{ version }}}
restart: always
env_file: {{ env }}
+ logging:
+ driver: journald
+ options:
+ tag: mailu-imap
volumes:
- "{{ root }}/mail:/mail"
- "{{ root }}/overrides/dovecot:/overrides:ro"
@@ -96,6 +110,10 @@ services:
image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}postfix:${MAILU_VERSION:-{{ version }}}
restart: always
env_file: {{ env }}
+ logging:
+ driver: journald
+ options:
+ tag: mailu-smtp
volumes:
- "{{ root }}/mailqueue:/queue"
- "{{ root }}/overrides/postfix:/overrides:ro"
@@ -127,6 +145,10 @@ services:
hostname: antispam
restart: always
env_file: {{ env }}
+ logging:
+ driver: journald
+ options:
+ tag: mailu-antispam
{% if oletools_enabled %}
networks:
- default
diff --git a/setup/flavors/compose/mailu.env b/setup/flavors/compose/mailu.env
index dce1cb27..090f4d3a 100644
--- a/setup/flavors/compose/mailu.env
+++ b/setup/flavors/compose/mailu.env
@@ -158,12 +158,6 @@ DOMAIN_REGISTRATION=true
# Advanced settings
###################################
-# Log driver for front service. Possible values:
-# json-file (default)
-# journald (On systemd platforms, useful for Fail2Ban integration)
-# syslog (Non systemd platforms, Fail2Ban integration. Disables `docker compose log` for front!)
-# LOG_DRIVER={{ log_driver or 'json-file' }}
-
# Docker-compose project name, this will prepended to containers names.
COMPOSE_PROJECT_NAME={{ compose_project_name or 'mailu' }}
diff --git a/setup/templates/steps/config.html b/setup/templates/steps/config.html
index b3b5fe87..025a2a2c 100644
--- a/setup/templates/steps/config.html
+++ b/setup/templates/steps/config.html
@@ -47,7 +47,7 @@ Or in plain english: if receivers start to classify your mail as spam, this post
/ day
+ value="50" required > / day
diff --git a/towncrier/newsfragments/2726.misc b/towncrier/newsfragments/2726.misc
new file mode 100644
index 00000000..f7eb41e3
--- /dev/null
+++ b/towncrier/newsfragments/2726.misc
@@ -0,0 +1 @@
+Change the behaviour of AUTH_RATELIMIT_USER and only account for distinct attempts. Same username and same password is now a only accounted once per period.
diff --git a/towncrier/newsfragments/2733.misc b/towncrier/newsfragments/2733.misc
new file mode 100644
index 00000000..8bc7777c
--- /dev/null
+++ b/towncrier/newsfragments/2733.misc
@@ -0,0 +1 @@
+Ensure we ask for the existing password before processing a password change request.
diff --git a/towncrier/newsfragments/2734.misc b/towncrier/newsfragments/2734.misc
new file mode 100644
index 00000000..b81098b6
--- /dev/null
+++ b/towncrier/newsfragments/2734.misc
@@ -0,0 +1,2 @@
+Remove LOG_DRIVER which never worked and replace it with journald by default
+Fix a bug where front may get attached to networks that don't exist