diff --git a/.env.dist b/.env.dist index 90b1ba0c..3d4a82b6 100644 --- a/.env.dist +++ b/.env.dist @@ -33,6 +33,9 @@ POSTMASTER=admin # Choose how secure connections will behave (value: letsencrypt, cert, notls) TLS_FLAVOR=cert +# Authentication rate limit (per source IP address) +AUTH_RATELIMIT=10/minute;1000/hour + ################################### # Optional features ################################### @@ -85,6 +88,12 @@ WEB_ADMIN=/admin # Path to the webmail if enabled WEB_WEBMAIL=/webmail +# Website name +SITENAME=Mailu + +# Linked Website URL +WEBSITE=https://mailu.io + ################################### # Advanced settings ################################### diff --git a/admin/mailu/__init__.py b/admin/mailu/__init__.py index 66641ffc..6b557a7e 100644 --- a/admin/mailu/__init__.py +++ b/admin/mailu/__init__.py @@ -5,6 +5,7 @@ import flask_login import flask_script import flask_migrate import flask_babel +import flask_limiter import os import docker @@ -20,6 +21,8 @@ default_config = { 'HOSTNAMES': 'mail.mailu.io', 'DOMAIN': 'mailu.io', 'POSTMASTER': 'postmaster', + 'SITENAME': 'Mailu', + 'WEBSITE': 'https://mailu.io', 'DEBUG': False, 'BOOTSTRAP_SERVE_LOCAL': True, 'DKIM_PATH': '/dkim/{domain}.{selector}.key', @@ -32,6 +35,9 @@ default_config = { 'TLS_FLAVOR': 'cert', 'CERTS_PATH': '/certs', 'PASSWORD_SCHEME': 'SHA512-CRYPT', + 'WEBMAIL': 'none', + 'AUTH_RATELIMIT': '10/minute;1000/hour', + 'RATELIMIT_STORAGE_URL': 'redis://redis' } # Load configuration from the environment if available @@ -42,6 +48,7 @@ for key, value in default_config.items(): flask_bootstrap.Bootstrap(app) db = flask_sqlalchemy.SQLAlchemy(app) migrate = flask_migrate.Migrate(app, db) +limiter = flask_limiter.Limiter(app, key_func=lambda: current_user.username) # Debugging toolbar if app.config.get("DEBUG"): @@ -72,8 +79,11 @@ def handle_needs_login(): ) @app.context_processor -def inject_user(): - return dict(current_user=flask_login.current_user) +def inject_defaults(): + return dict( + current_user=flask_login.current_user, + config=app.config + ) # Import views from mailu import ui, internal diff --git a/admin/mailu/internal/views.py b/admin/mailu/internal/views.py index 179b0cf5..dc893b66 100644 --- a/admin/mailu/internal/views.py +++ b/admin/mailu/internal/views.py @@ -1,10 +1,14 @@ -from mailu import db, models +from mailu import db, models, app, limiter from mailu.internal import internal, nginx import flask @internal.route("/auth/email") +@limiter.limit( + app.config["AUTH_RATELIMIT"], + lambda: flask.request.headers["Client-Ip"] +) def nginx_authentication(): """ Main authentication endpoint for Nginx email server """ diff --git a/admin/mailu/ui/templates/admin/create.html b/admin/mailu/ui/templates/admin/create.html index 6fe7e67b..060e5570 100644 --- a/admin/mailu/ui/templates/admin/create.html +++ b/admin/mailu/ui/templates/admin/create.html @@ -4,7 +4,8 @@ {% trans %}Add a global administrator{% endtrans %} {% endblock %} -{% block box_content %} +{% block content %} +{% call macros.box() %}
{{ form.hidden_tag() }} {{ macros.form_field(form.admin, id='admin') }} @@ -13,4 +14,5 @@ $("#admin").select2();
+{% endcall %} {% endblock %} diff --git a/admin/mailu/ui/templates/admin/list.html b/admin/mailu/ui/templates/admin/list.html index d286fb3f..72b5a1fa 100644 --- a/admin/mailu/ui/templates/admin/list.html +++ b/admin/mailu/ui/templates/admin/list.html @@ -10,21 +10,19 @@ {% endblock %} -{% block box %} - - - - - - - {% for admin in admins %} - - - - - {% endfor %} - -
{% trans %}Actions{% endtrans %}{% trans %}Email{% endtrans %}
- - {{ admin }}
+{% block content %} +{% call macros.table() %} + + {% trans %}Actions{% endtrans %} + {% trans %}Email{% endtrans %} + +{% for admin in admins %} + + + + + {{ admin }} + +{% endfor %} +{% endcall %} {% endblock %} diff --git a/admin/mailu/ui/templates/alias/create.html b/admin/mailu/ui/templates/alias/create.html index c848464b..9b176d36 100644 --- a/admin/mailu/ui/templates/alias/create.html +++ b/admin/mailu/ui/templates/alias/create.html @@ -8,7 +8,8 @@ {{ domain }} {% endblock %} -{% block box_content %} +{% block content %} +{% call macros.box() %}
{{ form.hidden_tag() }} {{ macros.form_field(form.localpart, append='@'+domain.name+'') }} @@ -23,4 +24,5 @@ })
+{% endcall %} {% endblock %} diff --git a/admin/mailu/ui/templates/alias/list.html b/admin/mailu/ui/templates/alias/list.html index d7380ef5..29766b25 100644 --- a/admin/mailu/ui/templates/alias/list.html +++ b/admin/mailu/ui/templates/alias/list.html @@ -12,30 +12,28 @@ {% trans %}Add alias{% endtrans %} {% endblock %} -{% block box %} - - - - - - - - - - - {% for alias in domain.aliases %} - - - - - - - - - {% endfor %} - -
{% trans %}Actions{% endtrans %}{% trans %}Email{% endtrans %}{% trans %}Destination{% endtrans %}{% trans %}Comment{% endtrans %}{% trans %}Created{% endtrans %}{% trans %}Last edit{% endtrans %}
-   - - {{ alias }}{{ alias.destination|join(', ') or '-' }}{{ alias.comment or '' }}{{ alias.created_at }}{{ alias.updated_at or '' }}
+{% block content %} +{% call macros.table() %} + + {% trans %}Actions{% endtrans %} + {% trans %}Email{% endtrans %} + {% trans %}Destination{% endtrans %} + {% trans %}Comment{% endtrans %} + {% trans %}Created{% endtrans %} + {% trans %}Last edit{% endtrans %} + +{% for alias in domain.aliases %} + + +   + + + {{ alias }} + {{ alias.destination|join(', ') or '-' }} + {{ alias.comment or '' }} + {{ alias.created_at }} + {{ alias.updated_at or '' }} + +{% endfor %} +{% endcall %} {% endblock %} diff --git a/admin/mailu/ui/templates/alternative/list.html b/admin/mailu/ui/templates/alternative/list.html index 547d2ecb..56e7565b 100644 --- a/admin/mailu/ui/templates/alternative/list.html +++ b/admin/mailu/ui/templates/alternative/list.html @@ -12,23 +12,21 @@ {% trans %}Add alternative{% endtrans %} {% endblock %} -{% block box %} - - - - - - - - {% for alternative in domain.alternatives %} - - - - - - {% endfor %} - -
{% trans %}Actions{% endtrans %}{% trans %}Name{% endtrans %}{% trans %}Created{% endtrans %}
- - {{ alternative }}{{ alternative.created_at }}
+{% block content %} +{% call macros.table() %} + + {% trans %}Actions{% endtrans %} + {% trans %}Name{% endtrans %} + {% trans %}Created{% endtrans %} + +{% for alternative in domain.alternatives %} + + + + + {{ alternative }} + {{ alternative.created_at }} + +{% endfor %} +{% endcall %} {% endblock %} diff --git a/admin/mailu/ui/templates/announcement.html b/admin/mailu/ui/templates/announcement.html index 6d080154..ced68297 100644 --- a/admin/mailu/ui/templates/announcement.html +++ b/admin/mailu/ui/templates/announcement.html @@ -8,11 +8,13 @@ {% trans %}from{% endtrans %} {{ from_address }} {% endblock %} -{% block box_content %} +{% block content %} +{% call macros.box() %}
{{ form.hidden_tag() }} {{ macros.form_field(form.announcement_subject) }} {{ macros.form_field(form.announcement_body, rows=10) }} {{ macros.form_field(form.submit) }}
+{% endcall %} {% endblock %} diff --git a/admin/mailu/ui/templates/base.html b/admin/mailu/ui/templates/base.html index 5fb0d8a9..0aa380c8 100644 --- a/admin/mailu/ui/templates/base.html +++ b/admin/mailu/ui/templates/base.html @@ -53,22 +53,7 @@ class="hold-transition skin-blue sidebar-mini"
{{ utils.flashed_messages(container=False) }} - {% block content %} -
-
-
- {% block box %} -
- {% block box_title %}{% endblock %} -
-
- {% block box_content %}{% endblock %} -
- {% endblock %} -
-
-
- {% endblock %} + {% block content %}{% endblock %}