diff --git a/.env.dist b/.env.dist
index 49365bc2..cb3a97d0 100644
--- a/.env.dist
+++ b/.env.dist
@@ -23,9 +23,7 @@ BIND_ADDRESS=127.0.0.1
# Main mail domain
DOMAIN=mailu.io
-# Main hostname for announces, and list of all available hostnames, separated
-# by comas
-HOSTNAME=mail.mailu.io
+# Hostnames for this server, separated with comas
HOSTNAMES=mail.mailu.io,alternative.mailu.io,yetanother.mailu.io
# Postmaster local part (will append the main mail domain)
@@ -38,8 +36,8 @@ TLS_FLAVOR=cert
# Optional features
###################################
-# Choose which frontend Web server to run if any (value: traefik, none)
-FRONTEND=none
+# Expose the admin interface (value: true, false)
+ADMIN=false
# Choose which webmail to run if any (values: roundcube, rainloop, none)
WEBMAIL=none
@@ -76,6 +74,16 @@ RECIPIENT_DELIMITER=+
DMARC_RUA=admin
DMARC_RUF=admin
+###################################
+# Web settings
+###################################
+
+# Path to the admin interface if enabled
+WEB_ADMIN=/admin
+
+# Path to the webmail if enabled
+WEB_WEBMAIL=/webmail
+
###################################
# Advanced settings
###################################
@@ -87,6 +95,3 @@ COMPOSE_PROJECT_NAME=mailu
# (value: SHA512-CRYPT, SHA256-CRYPT, MD5-CRYPT, CRYPT)
PASSWORD_SCHEME=SHA512-CRYPT
-# SSL DHPARAM Bits
-NGINX_SSL_DHPARAM_BITS=2048
-
diff --git a/admin/Dockerfile b/admin/Dockerfile
index 971b407b..78fa753e 100644
--- a/admin/Dockerfile
+++ b/admin/Dockerfile
@@ -5,7 +5,6 @@ WORKDIR /app
COPY requirements-prod.txt requirements.txt
RUN apk --update add --virtual build-dep openssl-dev libffi-dev python-dev build-base \
- && apk add openssl \
&& pip install -r requirements.txt \
&& apk del build-dep
diff --git a/admin/mailu/__init__.py b/admin/mailu/__init__.py
index aae26a4f..6d69621e 100644
--- a/admin/mailu/__init__.py
+++ b/admin/mailu/__init__.py
@@ -9,18 +9,15 @@ import flask_babel
import os
import docker
-from apscheduler.schedulers import background
-
-
# Create application
-app = flask.Flask(__name__, static_url_path='/admin/app_static')
+app = flask.Flask(__name__)
default_config = {
'SQLALCHEMY_DATABASE_URI': 'sqlite:////data/main.db',
'SQLALCHEMY_TRACK_MODIFICATIONS': False,
'SECRET_KEY': 'changeMe',
'DOCKER_SOCKET': 'unix:///var/run/docker.sock',
- 'HOSTNAME': 'mail.mailu.io',
+ 'HOSTNAMES': 'mail.mailu.io',
'DOMAIN': 'mailu.io',
'POSTMASTER': 'postmaster',
'DEBUG': False,
@@ -50,14 +47,6 @@ migrate = flask_migrate.Migrate(app, db)
manager = flask_script.Manager(app)
manager.add_command('db', flask_migrate.MigrateCommand)
-# Task scheduling
-scheduler = background.BackgroundScheduler({
- 'apscheduler.timezone': 'UTC'
-})
-if not app.debug or os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
- scheduler.start()
- from mailu import tlstasks
-
# Babel configuration
babel = flask_babel.Babel(app)
translations = list(map(str, babel.list_translations()))
@@ -82,7 +71,9 @@ def inject_user():
return dict(current_user=flask_login.current_user)
# Import views
-from mailu.views import *
+from mailu import ui, internal
+app.register_blueprint(ui.ui, url_prefix='/ui')
+app.register_blueprint(internal.internal, url_prefix='/internal')
# Create the prefix middleware
class PrefixMiddleware(object):
diff --git a/admin/mailu/internal/__init__.py b/admin/mailu/internal/__init__.py
new file mode 100644
index 00000000..9e8c3690
--- /dev/null
+++ b/admin/mailu/internal/__init__.py
@@ -0,0 +1,6 @@
+from flask import Blueprint
+
+
+internal = Blueprint('internal', __name__)
+
+from mailu.internal import views
diff --git a/admin/mailu/internal/nginx.py b/admin/mailu/internal/nginx.py
new file mode 100644
index 00000000..a7a8c5b4
--- /dev/null
+++ b/admin/mailu/internal/nginx.py
@@ -0,0 +1,70 @@
+from mailu import db, models
+
+import socket
+
+
+SUPPORTED_AUTH_METHODS = ["none", "plain"]
+
+STATUSES = {
+ "authentication": ("Authentication credentials invalid", {
+ "imap": "AUTHENTICATIONFAILED",
+ "smtp": "535 5.7.8",
+ "pop3": ""
+ }),
+}
+
+
+SERVER_MAP = {
+ "imap": ("imap", 143),
+ "smtp": ("smtp", 25)
+}
+
+
+def handle_authentication(headers):
+ """ Handle an HTTP nginx authentication request
+ See: http://nginx.org/en/docs/mail/ngx_mail_auth_http_module.html#protocol
+ """
+ method = headers["Auth-Method"]
+ protocol = headers["Auth-Protocol"]
+ server, port = get_server(headers["Auth-Protocol"])
+ # Incoming mail, no authentication
+ if method == "none" and protocol == "smtp":
+ return {
+ "Auth-Status": "OK",
+ "Auth-Server": server,
+ "Auth-Port": port
+ }
+ # Authenticated user
+ elif method == "plain":
+ user_email = headers["Auth-User"]
+ password = headers["Auth-Pass"]
+ user = models.User.query.get(user_email)
+ if user and user.check_password(password):
+ return {
+ "Auth-Status": "OK",
+ "Auth-Server": server,
+ "Auth-Port": port
+ }
+ else:
+ status, code = get_status(protocol, "authentication")
+ return {
+ "Auth-Status": status,
+ "Auth-Error-Code": code,
+ "Auth-Wait": 0
+ }
+ # Unexpected
+ else:
+ return {}
+
+
+def get_status(protocol, status):
+ """ Return the proper error code depending on the protocol
+ """
+ status, codes = STATUSES[status]
+ return status, codes[protocol]
+
+
+def get_server(protocol):
+ hostname, port = SERVER_MAP[protocol]
+ address = socket.gethostbyname(hostname)
+ return address, port
diff --git a/admin/mailu/internal/views.py b/admin/mailu/internal/views.py
new file mode 100644
index 00000000..04d3268a
--- /dev/null
+++ b/admin/mailu/internal/views.py
@@ -0,0 +1,13 @@
+from mailu import db, models
+from mailu.internal import internal, nginx
+
+import flask
+
+
+@internal.route("/nginx")
+def nginx_authentication():
+ headers = nginx.handle_authentication(flask.request.headers)
+ response = flask.Response()
+ for key, value in headers.items():
+ response.headers[key] = str(value)
+ return response
diff --git a/admin/mailu/tlstasks.py b/admin/mailu/tlstasks.py
deleted file mode 100644
index 0a0c9f2a..00000000
--- a/admin/mailu/tlstasks.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from mailu import app, scheduler, dockercli
-
-import urllib3
-import json
-import os
-import base64
-import subprocess
-
-
-def install_certs(domain):
- """ Extract certificates from the given domain and install them
- to the certificate path.
- """
- path = app.config["CERTS_PATH"]
- acme_path = os.path.join(path, "acme.json")
- key_path = os.path.join(path, "key.pem")
- cert_path = os.path.join(path, "cert.pem")
- if not os.path.exists(acme_path):
- print("Could not find traefik acme configuration")
- return
- with open(acme_path, "r") as handler:
- data = json.loads(handler.read())
- for item in data["DomainsCertificate"]["Certs"]:
- if domain == item["Domains"]["Main"]:
- cert = base64.b64decode(item["Certificate"]["Certificate"])
- key = base64.b64decode(item["Certificate"]["PrivateKey"])
- break
- else:
- print("Could not find the proper certificate from traefik")
- return
- if os.path.exists(cert_path):
- with open(cert_path, "rb") as handler:
- if handler.read() == cert:
- return
- print("Installing the new certificate from traefik")
- with open(cert_path, "wb") as handler:
- handler.write(cert)
- with open(key_path, "wb") as handler:
- handler.write(key)
-
-
-def restart_services():
- print("Reloading services using TLS")
- dockercli.reload("http", "smtp", "imap")
-
-
-@scheduler.scheduled_job('date')
-def create_dhparam():
- path = app.config["CERTS_PATH"]
- dhparam_path = os.path.join(path, "dhparam.pem")
- if not os.path.exists(dhparam_path):
- print("Creating DH params")
- subprocess.call(["openssl", "dhparam", "-out", dhparam_path, "2048"])
- restart_services()
-
-
-@scheduler.scheduled_job('date')
-@scheduler.scheduled_job('cron', day='*/4', hour=0, minute=0)
-def refresh_certs():
- if not app.config["TLS_FLAVOR"] == "letsencrypt":
- return
- if not app.config["FRONTEND"] == "traefik":
- print("Letsencrypt certificates are compatible with traefik only")
- return
- print("Requesting traefik to make sure the certificate is fresh")
- hostname = app.config["HOSTNAME"]
- urllib3.PoolManager().request("GET", "https://{}".format(hostname))
- install_certs(hostname)
diff --git a/admin/mailu/ui/__init__.py b/admin/mailu/ui/__init__.py
new file mode 100644
index 00000000..ec3601a1
--- /dev/null
+++ b/admin/mailu/ui/__init__.py
@@ -0,0 +1,6 @@
+from flask import Blueprint
+
+
+ui = Blueprint('ui', __name__, static_folder='static', template_folder='templates')
+
+from mailu.ui.views import *
diff --git a/admin/mailu/access.py b/admin/mailu/ui/access.py
similarity index 98%
rename from admin/mailu/access.py
rename to admin/mailu/ui/access.py
index b4179a53..2b6a3767 100644
--- a/admin/mailu/access.py
+++ b/admin/mailu/ui/access.py
@@ -1,4 +1,5 @@
-from mailu import db, models, forms
+from mailu import db, models
+from mailu.ui import forms
import flask
import flask_login
diff --git a/admin/mailu/forms.py b/admin/mailu/ui/forms.py
similarity index 100%
rename from admin/mailu/forms.py
rename to admin/mailu/ui/forms.py
diff --git a/admin/mailu/static/adminlte/css/AdminLTE.min.css b/admin/mailu/ui/static/adminlte/css/AdminLTE.min.css
similarity index 100%
rename from admin/mailu/static/adminlte/css/AdminLTE.min.css
rename to admin/mailu/ui/static/adminlte/css/AdminLTE.min.css
diff --git a/admin/mailu/static/adminlte/css/skin-blue.min.css b/admin/mailu/ui/static/adminlte/css/skin-blue.min.css
similarity index 100%
rename from admin/mailu/static/adminlte/css/skin-blue.min.css
rename to admin/mailu/ui/static/adminlte/css/skin-blue.min.css
diff --git a/admin/mailu/static/adminlte/js/app.min.js b/admin/mailu/ui/static/adminlte/js/app.min.js
similarity index 100%
rename from admin/mailu/static/adminlte/js/app.min.js
rename to admin/mailu/ui/static/adminlte/js/app.min.js
diff --git a/admin/mailu/static/app.css b/admin/mailu/ui/static/app.css
similarity index 100%
rename from admin/mailu/static/app.css
rename to admin/mailu/ui/static/app.css
diff --git a/admin/mailu/static/bootstrap/css/bootstrap.css.map b/admin/mailu/ui/static/bootstrap/css/bootstrap.css.map
similarity index 100%
rename from admin/mailu/static/bootstrap/css/bootstrap.css.map
rename to admin/mailu/ui/static/bootstrap/css/bootstrap.css.map
diff --git a/admin/mailu/static/bootstrap/css/bootstrap.min.css b/admin/mailu/ui/static/bootstrap/css/bootstrap.min.css
similarity index 100%
rename from admin/mailu/static/bootstrap/css/bootstrap.min.css
rename to admin/mailu/ui/static/bootstrap/css/bootstrap.min.css
diff --git a/admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.eot b/admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.eot
similarity index 100%
rename from admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.eot
rename to admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.eot
diff --git a/admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.svg b/admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.svg
similarity index 100%
rename from admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.svg
rename to admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.svg
diff --git a/admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.ttf b/admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.ttf
similarity index 100%
rename from admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.ttf
rename to admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.ttf
diff --git a/admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.woff b/admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.woff
similarity index 100%
rename from admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.woff
rename to admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.woff
diff --git a/admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.woff2 b/admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.woff2
similarity index 100%
rename from admin/mailu/static/bootstrap/fonts/glyphicons-halflings-regular.woff2
rename to admin/mailu/ui/static/bootstrap/fonts/glyphicons-halflings-regular.woff2
diff --git a/admin/mailu/static/bootstrap/js/bootstrap.min.js b/admin/mailu/ui/static/bootstrap/js/bootstrap.min.js
similarity index 100%
rename from admin/mailu/static/bootstrap/js/bootstrap.min.js
rename to admin/mailu/ui/static/bootstrap/js/bootstrap.min.js
diff --git a/admin/mailu/static/jquery/js/jquery-2.2.2.min.js b/admin/mailu/ui/static/jquery/js/jquery-2.2.2.min.js
similarity index 100%
rename from admin/mailu/static/jquery/js/jquery-2.2.2.min.js
rename to admin/mailu/ui/static/jquery/js/jquery-2.2.2.min.js
diff --git a/admin/mailu/static/select2/css/select2.min.css b/admin/mailu/ui/static/select2/css/select2.min.css
similarity index 100%
rename from admin/mailu/static/select2/css/select2.min.css
rename to admin/mailu/ui/static/select2/css/select2.min.css
diff --git a/admin/mailu/static/select2/js/i18n/ar.js b/admin/mailu/ui/static/select2/js/i18n/ar.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/ar.js
rename to admin/mailu/ui/static/select2/js/i18n/ar.js
diff --git a/admin/mailu/static/select2/js/i18n/az.js b/admin/mailu/ui/static/select2/js/i18n/az.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/az.js
rename to admin/mailu/ui/static/select2/js/i18n/az.js
diff --git a/admin/mailu/static/select2/js/i18n/bg.js b/admin/mailu/ui/static/select2/js/i18n/bg.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/bg.js
rename to admin/mailu/ui/static/select2/js/i18n/bg.js
diff --git a/admin/mailu/static/select2/js/i18n/ca.js b/admin/mailu/ui/static/select2/js/i18n/ca.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/ca.js
rename to admin/mailu/ui/static/select2/js/i18n/ca.js
diff --git a/admin/mailu/static/select2/js/i18n/cs.js b/admin/mailu/ui/static/select2/js/i18n/cs.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/cs.js
rename to admin/mailu/ui/static/select2/js/i18n/cs.js
diff --git a/admin/mailu/static/select2/js/i18n/da.js b/admin/mailu/ui/static/select2/js/i18n/da.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/da.js
rename to admin/mailu/ui/static/select2/js/i18n/da.js
diff --git a/admin/mailu/static/select2/js/i18n/de.js b/admin/mailu/ui/static/select2/js/i18n/de.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/de.js
rename to admin/mailu/ui/static/select2/js/i18n/de.js
diff --git a/admin/mailu/static/select2/js/i18n/el.js b/admin/mailu/ui/static/select2/js/i18n/el.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/el.js
rename to admin/mailu/ui/static/select2/js/i18n/el.js
diff --git a/admin/mailu/static/select2/js/i18n/en.js b/admin/mailu/ui/static/select2/js/i18n/en.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/en.js
rename to admin/mailu/ui/static/select2/js/i18n/en.js
diff --git a/admin/mailu/static/select2/js/i18n/es.js b/admin/mailu/ui/static/select2/js/i18n/es.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/es.js
rename to admin/mailu/ui/static/select2/js/i18n/es.js
diff --git a/admin/mailu/static/select2/js/i18n/et.js b/admin/mailu/ui/static/select2/js/i18n/et.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/et.js
rename to admin/mailu/ui/static/select2/js/i18n/et.js
diff --git a/admin/mailu/static/select2/js/i18n/eu.js b/admin/mailu/ui/static/select2/js/i18n/eu.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/eu.js
rename to admin/mailu/ui/static/select2/js/i18n/eu.js
diff --git a/admin/mailu/static/select2/js/i18n/fa.js b/admin/mailu/ui/static/select2/js/i18n/fa.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/fa.js
rename to admin/mailu/ui/static/select2/js/i18n/fa.js
diff --git a/admin/mailu/static/select2/js/i18n/fi.js b/admin/mailu/ui/static/select2/js/i18n/fi.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/fi.js
rename to admin/mailu/ui/static/select2/js/i18n/fi.js
diff --git a/admin/mailu/static/select2/js/i18n/fr.js b/admin/mailu/ui/static/select2/js/i18n/fr.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/fr.js
rename to admin/mailu/ui/static/select2/js/i18n/fr.js
diff --git a/admin/mailu/static/select2/js/i18n/gl.js b/admin/mailu/ui/static/select2/js/i18n/gl.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/gl.js
rename to admin/mailu/ui/static/select2/js/i18n/gl.js
diff --git a/admin/mailu/static/select2/js/i18n/he.js b/admin/mailu/ui/static/select2/js/i18n/he.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/he.js
rename to admin/mailu/ui/static/select2/js/i18n/he.js
diff --git a/admin/mailu/static/select2/js/i18n/hi.js b/admin/mailu/ui/static/select2/js/i18n/hi.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/hi.js
rename to admin/mailu/ui/static/select2/js/i18n/hi.js
diff --git a/admin/mailu/static/select2/js/i18n/hr.js b/admin/mailu/ui/static/select2/js/i18n/hr.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/hr.js
rename to admin/mailu/ui/static/select2/js/i18n/hr.js
diff --git a/admin/mailu/static/select2/js/i18n/hu.js b/admin/mailu/ui/static/select2/js/i18n/hu.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/hu.js
rename to admin/mailu/ui/static/select2/js/i18n/hu.js
diff --git a/admin/mailu/static/select2/js/i18n/id.js b/admin/mailu/ui/static/select2/js/i18n/id.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/id.js
rename to admin/mailu/ui/static/select2/js/i18n/id.js
diff --git a/admin/mailu/static/select2/js/i18n/is.js b/admin/mailu/ui/static/select2/js/i18n/is.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/is.js
rename to admin/mailu/ui/static/select2/js/i18n/is.js
diff --git a/admin/mailu/static/select2/js/i18n/it.js b/admin/mailu/ui/static/select2/js/i18n/it.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/it.js
rename to admin/mailu/ui/static/select2/js/i18n/it.js
diff --git a/admin/mailu/static/select2/js/i18n/ja.js b/admin/mailu/ui/static/select2/js/i18n/ja.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/ja.js
rename to admin/mailu/ui/static/select2/js/i18n/ja.js
diff --git a/admin/mailu/static/select2/js/i18n/km.js b/admin/mailu/ui/static/select2/js/i18n/km.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/km.js
rename to admin/mailu/ui/static/select2/js/i18n/km.js
diff --git a/admin/mailu/static/select2/js/i18n/ko.js b/admin/mailu/ui/static/select2/js/i18n/ko.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/ko.js
rename to admin/mailu/ui/static/select2/js/i18n/ko.js
diff --git a/admin/mailu/static/select2/js/i18n/lt.js b/admin/mailu/ui/static/select2/js/i18n/lt.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/lt.js
rename to admin/mailu/ui/static/select2/js/i18n/lt.js
diff --git a/admin/mailu/static/select2/js/i18n/lv.js b/admin/mailu/ui/static/select2/js/i18n/lv.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/lv.js
rename to admin/mailu/ui/static/select2/js/i18n/lv.js
diff --git a/admin/mailu/static/select2/js/i18n/mk.js b/admin/mailu/ui/static/select2/js/i18n/mk.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/mk.js
rename to admin/mailu/ui/static/select2/js/i18n/mk.js
diff --git a/admin/mailu/static/select2/js/i18n/ms.js b/admin/mailu/ui/static/select2/js/i18n/ms.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/ms.js
rename to admin/mailu/ui/static/select2/js/i18n/ms.js
diff --git a/admin/mailu/static/select2/js/i18n/nb.js b/admin/mailu/ui/static/select2/js/i18n/nb.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/nb.js
rename to admin/mailu/ui/static/select2/js/i18n/nb.js
diff --git a/admin/mailu/static/select2/js/i18n/nl.js b/admin/mailu/ui/static/select2/js/i18n/nl.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/nl.js
rename to admin/mailu/ui/static/select2/js/i18n/nl.js
diff --git a/admin/mailu/static/select2/js/i18n/pl.js b/admin/mailu/ui/static/select2/js/i18n/pl.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/pl.js
rename to admin/mailu/ui/static/select2/js/i18n/pl.js
diff --git a/admin/mailu/static/select2/js/i18n/pt-BR.js b/admin/mailu/ui/static/select2/js/i18n/pt-BR.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/pt-BR.js
rename to admin/mailu/ui/static/select2/js/i18n/pt-BR.js
diff --git a/admin/mailu/static/select2/js/i18n/pt.js b/admin/mailu/ui/static/select2/js/i18n/pt.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/pt.js
rename to admin/mailu/ui/static/select2/js/i18n/pt.js
diff --git a/admin/mailu/static/select2/js/i18n/ro.js b/admin/mailu/ui/static/select2/js/i18n/ro.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/ro.js
rename to admin/mailu/ui/static/select2/js/i18n/ro.js
diff --git a/admin/mailu/static/select2/js/i18n/ru.js b/admin/mailu/ui/static/select2/js/i18n/ru.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/ru.js
rename to admin/mailu/ui/static/select2/js/i18n/ru.js
diff --git a/admin/mailu/static/select2/js/i18n/sk.js b/admin/mailu/ui/static/select2/js/i18n/sk.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/sk.js
rename to admin/mailu/ui/static/select2/js/i18n/sk.js
diff --git a/admin/mailu/static/select2/js/i18n/sr-Cyrl.js b/admin/mailu/ui/static/select2/js/i18n/sr-Cyrl.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/sr-Cyrl.js
rename to admin/mailu/ui/static/select2/js/i18n/sr-Cyrl.js
diff --git a/admin/mailu/static/select2/js/i18n/sr.js b/admin/mailu/ui/static/select2/js/i18n/sr.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/sr.js
rename to admin/mailu/ui/static/select2/js/i18n/sr.js
diff --git a/admin/mailu/static/select2/js/i18n/sv.js b/admin/mailu/ui/static/select2/js/i18n/sv.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/sv.js
rename to admin/mailu/ui/static/select2/js/i18n/sv.js
diff --git a/admin/mailu/static/select2/js/i18n/th.js b/admin/mailu/ui/static/select2/js/i18n/th.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/th.js
rename to admin/mailu/ui/static/select2/js/i18n/th.js
diff --git a/admin/mailu/static/select2/js/i18n/tr.js b/admin/mailu/ui/static/select2/js/i18n/tr.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/tr.js
rename to admin/mailu/ui/static/select2/js/i18n/tr.js
diff --git a/admin/mailu/static/select2/js/i18n/uk.js b/admin/mailu/ui/static/select2/js/i18n/uk.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/uk.js
rename to admin/mailu/ui/static/select2/js/i18n/uk.js
diff --git a/admin/mailu/static/select2/js/i18n/vi.js b/admin/mailu/ui/static/select2/js/i18n/vi.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/vi.js
rename to admin/mailu/ui/static/select2/js/i18n/vi.js
diff --git a/admin/mailu/static/select2/js/i18n/zh-CN.js b/admin/mailu/ui/static/select2/js/i18n/zh-CN.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/zh-CN.js
rename to admin/mailu/ui/static/select2/js/i18n/zh-CN.js
diff --git a/admin/mailu/static/select2/js/i18n/zh-TW.js b/admin/mailu/ui/static/select2/js/i18n/zh-TW.js
similarity index 100%
rename from admin/mailu/static/select2/js/i18n/zh-TW.js
rename to admin/mailu/ui/static/select2/js/i18n/zh-TW.js
diff --git a/admin/mailu/static/select2/js/select2.full.min.js b/admin/mailu/ui/static/select2/js/select2.full.min.js
similarity index 100%
rename from admin/mailu/static/select2/js/select2.full.min.js
rename to admin/mailu/ui/static/select2/js/select2.full.min.js
diff --git a/admin/mailu/static/select2/js/select2.min.js b/admin/mailu/ui/static/select2/js/select2.min.js
similarity index 100%
rename from admin/mailu/static/select2/js/select2.min.js
rename to admin/mailu/ui/static/select2/js/select2.min.js
diff --git a/admin/mailu/templates/admin/create.html b/admin/mailu/ui/templates/admin/create.html
similarity index 100%
rename from admin/mailu/templates/admin/create.html
rename to admin/mailu/ui/templates/admin/create.html
diff --git a/admin/mailu/templates/admin/list.html b/admin/mailu/ui/templates/admin/list.html
similarity index 100%
rename from admin/mailu/templates/admin/list.html
rename to admin/mailu/ui/templates/admin/list.html
diff --git a/admin/mailu/templates/alias/create.html b/admin/mailu/ui/templates/alias/create.html
similarity index 100%
rename from admin/mailu/templates/alias/create.html
rename to admin/mailu/ui/templates/alias/create.html
diff --git a/admin/mailu/templates/alias/edit.html b/admin/mailu/ui/templates/alias/edit.html
similarity index 100%
rename from admin/mailu/templates/alias/edit.html
rename to admin/mailu/ui/templates/alias/edit.html
diff --git a/admin/mailu/templates/alias/list.html b/admin/mailu/ui/templates/alias/list.html
similarity index 100%
rename from admin/mailu/templates/alias/list.html
rename to admin/mailu/ui/templates/alias/list.html
diff --git a/admin/mailu/templates/alternative/create.html b/admin/mailu/ui/templates/alternative/create.html
similarity index 100%
rename from admin/mailu/templates/alternative/create.html
rename to admin/mailu/ui/templates/alternative/create.html
diff --git a/admin/mailu/templates/alternative/list.html b/admin/mailu/ui/templates/alternative/list.html
similarity index 100%
rename from admin/mailu/templates/alternative/list.html
rename to admin/mailu/ui/templates/alternative/list.html
diff --git a/admin/mailu/templates/announcement.html b/admin/mailu/ui/templates/announcement.html
similarity index 100%
rename from admin/mailu/templates/announcement.html
rename to admin/mailu/ui/templates/announcement.html
diff --git a/admin/mailu/templates/base.html b/admin/mailu/ui/templates/base.html
similarity index 100%
rename from admin/mailu/templates/base.html
rename to admin/mailu/ui/templates/base.html
diff --git a/admin/mailu/templates/confirm.html b/admin/mailu/ui/templates/confirm.html
similarity index 100%
rename from admin/mailu/templates/confirm.html
rename to admin/mailu/ui/templates/confirm.html
diff --git a/admin/mailu/templates/docker-error.html b/admin/mailu/ui/templates/docker-error.html
similarity index 100%
rename from admin/mailu/templates/docker-error.html
rename to admin/mailu/ui/templates/docker-error.html
diff --git a/admin/mailu/templates/domain/create.html b/admin/mailu/ui/templates/domain/create.html
similarity index 100%
rename from admin/mailu/templates/domain/create.html
rename to admin/mailu/ui/templates/domain/create.html
diff --git a/admin/mailu/templates/domain/details.html b/admin/mailu/ui/templates/domain/details.html
similarity index 89%
rename from admin/mailu/templates/domain/details.html
rename to admin/mailu/ui/templates/domain/details.html
index 1ae45e16..5b3655de 100644
--- a/admin/mailu/templates/domain/details.html
+++ b/admin/mailu/ui/templates/domain/details.html
@@ -15,6 +15,7 @@
{% endblock %}
{% block box %}
+{% let hostname = config["HOSTNAMES"].split(",")[0] %}
@@ -28,8 +29,8 @@
{% trans %}DNS SPF entries{% endtrans %} |
-{{ domain.name }}. 600 IN TXT "v=spf1 mx a:{{ config["HOSTNAME"] }} -all"
-{{ domain.name }}. 600 IN SPF "v=spf1 mx a:{{ config["HOSTNAME"] }} -all" |
+{{ domain.name }}. 600 IN TXT "v=spf1 mx a:{{ hostname }} -all"
+{{ domain.name }}. 600 IN SPF "v=spf1 mx a:{{ hostname }} -all"
{% if domain.dkim_publickey %}
diff --git a/admin/mailu/templates/domain/edit.html b/admin/mailu/ui/templates/domain/edit.html
similarity index 100%
rename from admin/mailu/templates/domain/edit.html
rename to admin/mailu/ui/templates/domain/edit.html
diff --git a/admin/mailu/templates/domain/list.html b/admin/mailu/ui/templates/domain/list.html
similarity index 100%
rename from admin/mailu/templates/domain/list.html
rename to admin/mailu/ui/templates/domain/list.html
diff --git a/admin/mailu/templates/fetch/create.html b/admin/mailu/ui/templates/fetch/create.html
similarity index 100%
rename from admin/mailu/templates/fetch/create.html
rename to admin/mailu/ui/templates/fetch/create.html
diff --git a/admin/mailu/templates/fetch/edit.html b/admin/mailu/ui/templates/fetch/edit.html
similarity index 100%
rename from admin/mailu/templates/fetch/edit.html
rename to admin/mailu/ui/templates/fetch/edit.html
diff --git a/admin/mailu/templates/fetch/list.html b/admin/mailu/ui/templates/fetch/list.html
similarity index 100%
rename from admin/mailu/templates/fetch/list.html
rename to admin/mailu/ui/templates/fetch/list.html
diff --git a/admin/mailu/templates/form.html b/admin/mailu/ui/templates/form.html
similarity index 100%
rename from admin/mailu/templates/form.html
rename to admin/mailu/ui/templates/form.html
diff --git a/admin/mailu/templates/helpers.html b/admin/mailu/ui/templates/helpers.html
similarity index 100%
rename from admin/mailu/templates/helpers.html
rename to admin/mailu/ui/templates/helpers.html
diff --git a/admin/mailu/templates/index.html b/admin/mailu/ui/templates/index.html
similarity index 100%
rename from admin/mailu/templates/index.html
rename to admin/mailu/ui/templates/index.html
diff --git a/admin/mailu/templates/login.html b/admin/mailu/ui/templates/login.html
similarity index 100%
rename from admin/mailu/templates/login.html
rename to admin/mailu/ui/templates/login.html
diff --git a/admin/mailu/templates/macros.html b/admin/mailu/ui/templates/macros.html
similarity index 100%
rename from admin/mailu/templates/macros.html
rename to admin/mailu/ui/templates/macros.html
diff --git a/admin/mailu/templates/manager/create.html b/admin/mailu/ui/templates/manager/create.html
similarity index 100%
rename from admin/mailu/templates/manager/create.html
rename to admin/mailu/ui/templates/manager/create.html
diff --git a/admin/mailu/templates/manager/list.html b/admin/mailu/ui/templates/manager/list.html
similarity index 100%
rename from admin/mailu/templates/manager/list.html
rename to admin/mailu/ui/templates/manager/list.html
diff --git a/admin/mailu/templates/relay/create.html b/admin/mailu/ui/templates/relay/create.html
similarity index 100%
rename from admin/mailu/templates/relay/create.html
rename to admin/mailu/ui/templates/relay/create.html
diff --git a/admin/mailu/templates/relay/edit.html b/admin/mailu/ui/templates/relay/edit.html
similarity index 100%
rename from admin/mailu/templates/relay/edit.html
rename to admin/mailu/ui/templates/relay/edit.html
diff --git a/admin/mailu/templates/relay/list.html b/admin/mailu/ui/templates/relay/list.html
similarity index 100%
rename from admin/mailu/templates/relay/list.html
rename to admin/mailu/ui/templates/relay/list.html
diff --git a/admin/mailu/templates/services.html b/admin/mailu/ui/templates/services.html
similarity index 100%
rename from admin/mailu/templates/services.html
rename to admin/mailu/ui/templates/services.html
diff --git a/admin/mailu/templates/sidebar.html b/admin/mailu/ui/templates/sidebar.html
similarity index 100%
rename from admin/mailu/templates/sidebar.html
rename to admin/mailu/ui/templates/sidebar.html
diff --git a/admin/mailu/templates/user/create.html b/admin/mailu/ui/templates/user/create.html
similarity index 100%
rename from admin/mailu/templates/user/create.html
rename to admin/mailu/ui/templates/user/create.html
diff --git a/admin/mailu/templates/user/edit.html b/admin/mailu/ui/templates/user/edit.html
similarity index 100%
rename from admin/mailu/templates/user/edit.html
rename to admin/mailu/ui/templates/user/edit.html
diff --git a/admin/mailu/templates/user/forward.html b/admin/mailu/ui/templates/user/forward.html
similarity index 100%
rename from admin/mailu/templates/user/forward.html
rename to admin/mailu/ui/templates/user/forward.html
diff --git a/admin/mailu/templates/user/list.html b/admin/mailu/ui/templates/user/list.html
similarity index 100%
rename from admin/mailu/templates/user/list.html
rename to admin/mailu/ui/templates/user/list.html
diff --git a/admin/mailu/templates/user/password.html b/admin/mailu/ui/templates/user/password.html
similarity index 100%
rename from admin/mailu/templates/user/password.html
rename to admin/mailu/ui/templates/user/password.html
diff --git a/admin/mailu/templates/user/reply.html b/admin/mailu/ui/templates/user/reply.html
similarity index 100%
rename from admin/mailu/templates/user/reply.html
rename to admin/mailu/ui/templates/user/reply.html
diff --git a/admin/mailu/templates/user/settings.html b/admin/mailu/ui/templates/user/settings.html
similarity index 100%
rename from admin/mailu/templates/user/settings.html
rename to admin/mailu/ui/templates/user/settings.html
diff --git a/admin/mailu/templates/working.html b/admin/mailu/ui/templates/working.html
similarity index 100%
rename from admin/mailu/templates/working.html
rename to admin/mailu/ui/templates/working.html
diff --git a/admin/mailu/views/__init__.py b/admin/mailu/ui/views/__init__.py
similarity index 100%
rename from admin/mailu/views/__init__.py
rename to admin/mailu/ui/views/__init__.py
diff --git a/admin/mailu/views/admins.py b/admin/mailu/ui/views/admins.py
similarity index 86%
rename from admin/mailu/views/admins.py
rename to admin/mailu/ui/views/admins.py
index bbefaa1a..e9771ec6 100644
--- a/admin/mailu/views/admins.py
+++ b/admin/mailu/ui/views/admins.py
@@ -1,17 +1,18 @@
-from mailu import app, db, models, forms, access
+from mailu import db, models
+from mailu.ui import ui, forms, access
import flask
import flask_login
-@app.route('/admin/list', methods=['GET'])
+@ui.route('/admin/list', methods=['GET'])
@access.global_admin
def admin_list():
admins = models.User.query.filter_by(global_admin=True)
return flask.render_template('admin/list.html', admins=admins)
-@app.route('/admin/create', methods=['GET', 'POST'])
+@ui.route('/admin/create', methods=['GET', 'POST'])
@access.global_admin
def admin_create():
form = forms.AdminForm()
@@ -32,7 +33,7 @@ def admin_create():
return flask.render_template('admin/create.html', form=form)
-@app.route('/admin/delete/', methods=['GET', 'POST'])
+@ui.route('/admin/delete/', methods=['GET', 'POST'])
@access.global_admin
@access.confirmation_required("delete admin {admin}")
def admin_delete(admin):
diff --git a/admin/mailu/views/aliases.py b/admin/mailu/ui/views/aliases.py
similarity index 87%
rename from admin/mailu/views/aliases.py
rename to admin/mailu/ui/views/aliases.py
index c61e5715..7fc03266 100644
--- a/admin/mailu/views/aliases.py
+++ b/admin/mailu/ui/views/aliases.py
@@ -1,17 +1,18 @@
-from mailu import app, db, models, forms, access
+from mailu import db, models
+from mailu.ui import ui, forms, access
import flask
import wtforms_components
-@app.route('/alias/list/', methods=['GET'])
+@ui.route('/alias/list/', methods=['GET'])
@access.domain_admin(models.Domain, 'domain_name')
def alias_list(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
return flask.render_template('alias/list.html', domain=domain)
-@app.route('/alias/create/', methods=['GET', 'POST'])
+@ui.route('/alias/create/', methods=['GET', 'POST'])
@access.domain_admin(models.Domain, 'domain_name')
def alias_create(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
@@ -35,7 +36,7 @@ def alias_create(domain_name):
domain=domain, form=form)
-@app.route('/alias/edit/', methods=['GET', 'POST'])
+@ui.route('/alias/edit/', methods=['GET', 'POST'])
@access.domain_admin(models.Alias, 'alias')
def alias_edit(alias):
alias = models.Alias.query.get(alias) or flask.abort(404)
@@ -52,7 +53,7 @@ def alias_edit(alias):
form=form, alias=alias, domain=alias.domain)
-@app.route('/alias/delete/', methods=['GET', 'POST'])
+@ui.route('/alias/delete/', methods=['GET', 'POST'])
@access.domain_admin(models.Alias, 'alias')
@access.confirmation_required("delete {alias}")
def alias_delete(alias):
diff --git a/admin/mailu/views/alternatives.py b/admin/mailu/ui/views/alternatives.py
similarity index 86%
rename from admin/mailu/views/alternatives.py
rename to admin/mailu/ui/views/alternatives.py
index aa13bd3a..79acb074 100644
--- a/admin/mailu/views/alternatives.py
+++ b/admin/mailu/ui/views/alternatives.py
@@ -1,17 +1,18 @@
-from mailu import app, db, models, forms, access
+from mailu import db, models
+from mailu.ui import ui, forms, access
import flask
import wtforms_components
-@app.route('/alternative/list/', methods=['GET'])
+@ui.route('/alternative/list/', methods=['GET'])
@access.global_admin
def alternative_list(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
return flask.render_template('alternative/list.html', domain=domain)
-@app.route('/alternative/create/', methods=['GET', 'POST'])
+@ui.route('/alternative/create/', methods=['GET', 'POST'])
@access.global_admin
def alternative_create(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
@@ -34,7 +35,7 @@ def alternative_create(domain_name):
domain=domain, form=form)
-@app.route('/alternative/delete/', methods=['GET', 'POST'])
+@ui.route('/alternative/delete/', methods=['GET', 'POST'])
@access.global_admin
@access.confirmation_required("delete {alternative}")
def alternative_delete(alternative):
diff --git a/admin/mailu/views/base.py b/admin/mailu/ui/views/base.py
similarity index 84%
rename from admin/mailu/views/base.py
rename to admin/mailu/ui/views/base.py
index 850c06ff..eae240e1 100644
--- a/admin/mailu/views/base.py
+++ b/admin/mailu/ui/views/base.py
@@ -1,4 +1,5 @@
-from mailu import dockercli, app, db, models, forms, access
+from mailu import dockercli, app, db, models
+from mailu.ui import ui, forms, access
import flask
import flask_login
@@ -8,18 +9,13 @@ from email.mime import text
from urllib import parse
-@app.route('/home', methods=["GET"])
-def home():
- return flask.redirect('/webmail/')
-
-
-@app.route('/', methods=["GET"])
+@ui.route('/', methods=["GET"])
@access.authenticated
def index():
return flask.redirect(flask.url_for('.user_settings'))
-@app.route('/login', methods=['GET', 'POST'])
+@ui.route('/login', methods=['GET', 'POST'])
def login():
form = forms.LoginForm()
if form.validate_on_submit():
@@ -34,14 +30,14 @@ def login():
return flask.render_template('login.html', form=form)
-@app.route('/logout', methods=['GET'])
+@ui.route('/logout', methods=['GET'])
@access.authenticated
def logout():
flask_login.logout_user()
return flask.redirect(flask.url_for('.index'))
-@app.route('/services', methods=['GET'])
+@ui.route('/services', methods=['GET'])
@access.global_admin
def services():
try:
@@ -51,7 +47,7 @@ def services():
return flask.render_template('services.html', containers=containers)
-@app.route('/announcement', methods=['GET', 'POST'])
+@ui.route('/announcement', methods=['GET', 'POST'])
@access.global_admin
def announcement():
from_address = '{}@{}'.format(
diff --git a/admin/mailu/views/domains.py b/admin/mailu/ui/views/domains.py
similarity index 85%
rename from admin/mailu/views/domains.py
rename to admin/mailu/ui/views/domains.py
index f2542d4d..f1145e83 100644
--- a/admin/mailu/views/domains.py
+++ b/admin/mailu/ui/views/domains.py
@@ -1,16 +1,17 @@
-from mailu import app, db, models, forms, access
+from mailu import app, db, models
+from mailu.ui import ui, forms, access
import flask
import wtforms_components
-@app.route('/domain', methods=['GET'])
+@ui.route('/domain', methods=['GET'])
@access.authenticated
def domain_list():
return flask.render_template('domain/list.html')
-@app.route('/domain/create', methods=['GET', 'POST'])
+@ui.route('/domain/create', methods=['GET', 'POST'])
@access.global_admin
def domain_create():
form = forms.DomainForm()
@@ -30,7 +31,7 @@ def domain_create():
return flask.render_template('domain/create.html', form=form)
-@app.route('/domain/edit/', methods=['GET', 'POST'])
+@ui.route('/domain/edit/', methods=['GET', 'POST'])
@access.global_admin
def domain_edit(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
@@ -46,7 +47,7 @@ def domain_edit(domain_name):
domain=domain)
-@app.route('/domain/delete/', methods=['GET', 'POST'])
+@ui.route('/domain/delete/', methods=['GET', 'POST'])
@access.global_admin
@access.confirmation_required("delete {domain_name}")
def domain_delete(domain_name):
@@ -57,7 +58,7 @@ def domain_delete(domain_name):
return flask.redirect(flask.url_for('.domain_list'))
-@app.route('/domain/details/', methods=['GET'])
+@ui.route('/domain/details/', methods=['GET'])
@access.domain_admin(models.Domain, 'domain_name')
def domain_details(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
@@ -65,7 +66,7 @@ def domain_details(domain_name):
config=app.config)
-@app.route('/domain/genkeys/', methods=['GET', 'POST'])
+@ui.route('/domain/genkeys/', methods=['GET', 'POST'])
@access.domain_admin(models.Domain, 'domain_name')
@access.confirmation_required("regenerate keys for {domain_name}")
def domain_genkeys(domain_name):
diff --git a/admin/mailu/views/fetches.py b/admin/mailu/ui/views/fetches.py
similarity index 79%
rename from admin/mailu/views/fetches.py
rename to admin/mailu/ui/views/fetches.py
index e3be2bdd..b4ddb824 100644
--- a/admin/mailu/views/fetches.py
+++ b/admin/mailu/ui/views/fetches.py
@@ -1,11 +1,12 @@
-from mailu import app, db, models, forms, access
+from mailu import db, models
+from mailu.ui import ui, forms, access
import flask
import flask_login
-@app.route('/fetch/list', methods=['GET', 'POST'], defaults={'user_email': None})
-@app.route('/fetch/list/', methods=['GET'])
+@ui.route('/fetch/list', methods=['GET', 'POST'], defaults={'user_email': None})
+@ui.route('/fetch/list/', methods=['GET'])
@access.owner(models.User, 'user_email')
def fetch_list(user_email):
user_email = user_email or flask_login.current_user.email
@@ -13,8 +14,8 @@ def fetch_list(user_email):
return flask.render_template('fetch/list.html', user=user)
-@app.route('/fetch/create', methods=['GET', 'POST'], defaults={'user_email': None})
-@app.route('/fetch/create/', methods=['GET', 'POST'])
+@ui.route('/fetch/create', methods=['GET', 'POST'], defaults={'user_email': None})
+@ui.route('/fetch/create/', methods=['GET', 'POST'])
@access.owner(models.User, 'user_email')
def fetch_create(user_email):
user_email = user_email or flask_login.current_user.email
@@ -31,7 +32,7 @@ def fetch_create(user_email):
return flask.render_template('fetch/create.html', form=form)
-@app.route('/fetch/edit/', methods=['GET', 'POST'])
+@ui.route('/fetch/edit/', methods=['GET', 'POST'])
@access.owner(models.Fetch, 'fetch_id')
def fetch_edit(fetch_id):
fetch = models.Fetch.query.get(fetch_id) or flask.abort(404)
@@ -46,7 +47,7 @@ def fetch_edit(fetch_id):
form=form, fetch=fetch)
-@app.route('/fetch/delete/', methods=['GET', 'POST'])
+@ui.route('/fetch/delete/', methods=['GET', 'POST'])
@access.confirmation_required("delete a fetched account")
@access.owner(models.Fetch, 'fetch_id')
def fetch_delete(fetch_id):
diff --git a/admin/mailu/views/managers.py b/admin/mailu/ui/views/managers.py
similarity index 87%
rename from admin/mailu/views/managers.py
rename to admin/mailu/ui/views/managers.py
index 731ee1c7..15ebcd50 100644
--- a/admin/mailu/views/managers.py
+++ b/admin/mailu/ui/views/managers.py
@@ -1,17 +1,18 @@
-from mailu import app, db, models, forms, access
+from mailu import db, models
+from mailu.ui import ui, forms, access
import flask
import flask_login
-@app.route('/manager/list/', methods=['GET'])
+@ui.route('/manager/list/', methods=['GET'])
@access.domain_admin(models.Domain, 'domain_name')
def manager_list(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
return flask.render_template('manager/list.html', domain=domain)
-@app.route('/manager/create/', methods=['GET', 'POST'])
+@ui.route('/manager/create/', methods=['GET', 'POST'])
@access.domain_admin(models.Domain, 'domain_name')
def manager_create(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
@@ -37,7 +38,7 @@ def manager_create(domain_name):
domain=domain, form=form)
-@app.route('/manager/delete//', methods=['GET', 'POST'])
+@ui.route('/manager/delete//', methods=['GET', 'POST'])
@access.confirmation_required("remove manager {user_email}")
@access.domain_admin(models.Domain, 'domain_name')
def manager_delete(domain_name, user_email):
diff --git a/admin/mailu/views/relays.py b/admin/mailu/ui/views/relays.py
similarity index 86%
rename from admin/mailu/views/relays.py
rename to admin/mailu/ui/views/relays.py
index 599f2514..a0ddc614 100644
--- a/admin/mailu/views/relays.py
+++ b/admin/mailu/ui/views/relays.py
@@ -1,17 +1,18 @@
-from mailu import app, db, models, forms, access
+from mailu import db, models
+from mailu.ui import ui, forms, access
import flask
import wtforms_components
-@app.route('/relay', methods=['GET'])
+@ui.route('/relay', methods=['GET'])
@access.global_admin
def relay_list():
relays = models.Relay.query.all()
return flask.render_template('relay/list.html', relays=relays)
-@app.route('/relay/create', methods=['GET', 'POST'])
+@ui.route('/relay/create', methods=['GET', 'POST'])
@access.global_admin
def relay_create():
form = forms.RelayForm()
@@ -31,7 +32,7 @@ def relay_create():
return flask.render_template('relay/create.html', form=form)
-@app.route('/relay/edit/', methods=['GET', 'POST'])
+@ui.route('/relay/edit/', methods=['GET', 'POST'])
@access.global_admin
def relay_edit(relay_name):
relay = models.Relay.query.get(relay_name) or flask.abort(404)
@@ -47,7 +48,7 @@ def relay_edit(relay_name):
relay=relay)
-@app.route('/relay/delete/', methods=['GET', 'POST'])
+@ui.route('/relay/delete/', methods=['GET', 'POST'])
@access.global_admin
@access.confirmation_required("delete {relay_name}")
def relay_delete(relay_name):
diff --git a/admin/mailu/views/users.py b/admin/mailu/ui/views/users.py
similarity index 86%
rename from admin/mailu/views/users.py
rename to admin/mailu/ui/views/users.py
index 1e6c533a..dd787bc9 100644
--- a/admin/mailu/views/users.py
+++ b/admin/mailu/ui/views/users.py
@@ -1,4 +1,5 @@
-from mailu import app, db, models, forms, access
+from mailu import db, models
+from mailu.ui import ui, access, forms
import flask
import flask_login
@@ -6,14 +7,14 @@ import wtforms
import wtforms_components
-@app.route('/user/list/', methods=['GET'])
+@ui.route('/user/list/', methods=['GET'])
@access.domain_admin(models.Domain, 'domain_name')
def user_list(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
return flask.render_template('user/list.html', domain=domain)
-@app.route('/user/create/', methods=['GET', 'POST'])
+@ui.route('/user/create/', methods=['GET', 'POST'])
@access.domain_admin(models.Domain, 'domain_name')
def user_create(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404)
@@ -41,7 +42,7 @@ def user_create(domain_name):
domain=domain, form=form)
-@app.route('/user/edit/', methods=['GET', 'POST'])
+@ui.route('/user/edit/', methods=['GET', 'POST'])
@access.domain_admin(models.User, 'user_email')
def user_edit(user_email):
user = models.User.query.get(user_email) or flask.abort(404)
@@ -69,7 +70,7 @@ def user_edit(user_email):
domain=user.domain, max_quota_bytes=max_quota_bytes)
-@app.route('/user/delete/', methods=['GET', 'POST'])
+@ui.route('/user/delete/', methods=['GET', 'POST'])
@access.domain_admin(models.User, 'user_email')
@access.confirmation_required("delete {user_email}")
def user_delete(user_email):
@@ -82,8 +83,8 @@ def user_delete(user_email):
flask.url_for('.user_list', domain_name=domain.name))
-@app.route('/user/settings', methods=['GET', 'POST'], defaults={'user_email': None})
-@app.route('/user/usersettings/', methods=['GET', 'POST'])
+@ui.route('/user/settings', methods=['GET', 'POST'], defaults={'user_email': None})
+@ui.route('/user/usersettings/', methods=['GET', 'POST'])
@access.owner(models.User, 'user_email')
def user_settings(user_email):
user_email_or_current = user_email or flask_login.current_user.email
@@ -99,8 +100,8 @@ def user_settings(user_email):
return flask.render_template('user/settings.html', form=form, user=user)
-@app.route('/user/password', methods=['GET', 'POST'], defaults={'user_email': None})
-@app.route('/user/password/', methods=['GET', 'POST'])
+@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):
user_email_or_current = user_email or flask_login.current_user.email
@@ -119,8 +120,8 @@ def user_password(user_email):
return flask.render_template('user/password.html', form=form, user=user)
-@app.route('/user/forward', methods=['GET', 'POST'], defaults={'user_email': None})
-@app.route('/user/forward/', methods=['GET', 'POST'])
+@ui.route('/user/forward', methods=['GET', 'POST'], defaults={'user_email': None})
+@ui.route('/user/forward/', methods=['GET', 'POST'])
@access.owner(models.User, 'user_email')
def user_forward(user_email):
user_email_or_current = user_email or flask_login.current_user.email
@@ -136,8 +137,8 @@ def user_forward(user_email):
return flask.render_template('user/forward.html', form=form, user=user)
-@app.route('/user/reply', methods=['GET', 'POST'], defaults={'user_email': None})
-@app.route('/user/reply/', methods=['GET', 'POST'])
+@ui.route('/user/reply', methods=['GET', 'POST'], defaults={'user_email': None})
+@ui.route('/user/reply/', methods=['GET', 'POST'])
@access.owner(models.User, 'user_email')
def user_reply(user_email):
user_email_or_current = user_email or flask_login.current_user.email
diff --git a/admin/requirements-prod.txt b/admin/requirements-prod.txt
index 43c10f0b..d5ec8472 100644
--- a/admin/requirements-prod.txt
+++ b/admin/requirements-prod.txt
@@ -1,5 +1,4 @@
alembic==0.9.5
-APScheduler==3.3.1
asn1crypto==0.22.0
Babel==2.5.1
certifi==2017.7.27.1
diff --git a/admin/requirements.txt b/admin/requirements.txt
index 4c069a89..47d3147b 100644
--- a/admin/requirements.txt
+++ b/admin/requirements.txt
@@ -11,6 +11,5 @@ passlib
gunicorn
docker-py
tabulate
-apscheduler
PyYAML
PyOpenSSL
diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist
index 11b5079f..35f6ac5f 100644
--- a/docker-compose.yml.dist
+++ b/docker-compose.yml.dist
@@ -2,17 +2,23 @@ version: '2'
services:
- http:
- # build: $FRONTEND
- image: mailu/$FRONTEND:$VERSION
+ front:
+ # build: nginx
+ image: mailu/nginx:$VERSION
restart: always
env_file: .env
ports:
- "$BIND_ADDRESS:80:80"
- "$BIND_ADDRESS:443:443"
+ - "$BIND_ADDRESS:110:110"
+ - "$BIND_ADDRESS:143:143"
+ - "$BIND_ADDRESS:993:993"
+ - "$BIND_ADDRESS:995:995"
+ - "$BIND_ADDRESS:25:25"
+ - "$BIND_ADDRESS:465:465"
+ - "$BIND_ADDRESS:587:587"
volumes:
- "$ROOT/certs:/certs"
- - /var/run/docker.sock:/docker.sock:ro
redis:
image: redis:latest
@@ -25,16 +31,9 @@ services:
image: mailu/dovecot:$VERSION
restart: always
env_file: .env
- ports:
- - "$BIND_ADDRESS:110:110"
- - "$BIND_ADDRESS:143:143"
- - "$BIND_ADDRESS:993:993"
- - "$BIND_ADDRESS:995:995"
- - "$BIND_ADDRESS:4190:4190"
volumes:
- "$ROOT/data:/data"
- "$ROOT/mail:/mail"
- - "$ROOT/certs:/certs"
- "$ROOT/overrides:/overrides"
smtp:
@@ -42,13 +41,8 @@ services:
image: mailu/postfix:$VERSION
restart: always
env_file: .env
- ports:
- - "$BIND_ADDRESS:25:25"
- - "$BIND_ADDRESS:465:465"
- - "$BIND_ADDRESS:587:587"
volumes:
- "$ROOT/data:/data"
- - "$ROOT/certs:/certs"
- "$ROOT/overrides:/overrides"
milter:
@@ -88,29 +82,16 @@ services:
admin:
# build: admin
image: mailu/admin:$VERSION
- labels:
- - traefik.enable=true
- - traefik.admin.frontend.rule=Host:$HOSTNAME;PathPrefixStrip:/admin/
- - traefik.admin.port=80
- - traefik.home.frontend.rule=Host:$HOSTNAME;Path:/
- - traefik.home.port=80
restart: always
env_file: .env
- ports:
- - "127.0.0.1:8000:80"
volumes:
- "$ROOT/data:/data"
- "$ROOT/dkim:/dkim"
- - "$ROOT/certs:/certs"
- /var/run/docker.sock:/var/run/docker.sock:ro
webmail:
# build: "$WEBMAIL"
image: "mailu/$WEBMAIL:$VERSION"
- labels:
- - traefik.enable=true
- - traefik.frontend.rule=Host:$HOSTNAME;PathPrefixStrip:/webmail/
- - traefik.port=80
restart: always
env_file: .env
volumes:
diff --git a/dovecot/Dockerfile b/dovecot/Dockerfile
index ee80fe42..9e87f12f 100644
--- a/dovecot/Dockerfile
+++ b/dovecot/Dockerfile
@@ -3,12 +3,10 @@ FROM alpine:edge
RUN echo "@testing http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \
&& apk add --no-cache \
dovecot dovecot-sqlite dovecot-pigeonhole-plugin dovecot-pigeonhole-plugin-extdata \
- rspamd-client@testing \
- bash
+ rspamd-client@testing python py-jinja2
-COPY conf /etc/dovecot
+COPY conf /conf
COPY sieve /var/lib/dovecot
+COPY start.py /start.py
-COPY start.sh /start.sh
-
-CMD ["/start.sh"]
+CMD /start.py
diff --git a/dovecot/conf/dovecot-sql.conf.ext b/dovecot/conf/dovecot-sql.conf.ext
index e42abb84..d2e31016 100644
--- a/dovecot/conf/dovecot-sql.conf.ext
+++ b/dovecot/conf/dovecot-sql.conf.ext
@@ -3,7 +3,7 @@ connect = /data/main.db
# Return the user hashed password
password_query = \
- SELECT password \
+ SELECT NULL as password, 'Y' as nopassword, '{{ FRONT_ADDRESS }}' as allow_nets \
FROM user \
WHERE user.email = '%u'
diff --git a/dovecot/conf/dovecot.conf b/dovecot/conf/dovecot.conf
index faa41bf7..98cff4bc 100644
--- a/dovecot/conf/dovecot.conf
+++ b/dovecot/conf/dovecot.conf
@@ -4,7 +4,7 @@
log_path = /dev/stderr
protocols = imap pop3 lmtp sieve
postmaster_address = {{ POSTMASTER }}@{{ DOMAIN }}
-hostname = {{ HOSTNAME }}
+hostname = {{ HOSTNAMES.split(",")[0] }}
mail_plugins = $mail_plugins quota
submission_host = smtp
@@ -52,27 +52,11 @@ namespace inbox {
}
}
-###############
-# TLS
-###############
-ssl = yes
-ssl_cert = /dev/null 2>&1; then
- cp /overrides/*.map /etc/postfix/
- postmap /etc/postfix/*.map
- rm /etc/postfix/*.map
- chown root:root /etc/postfix/*.db
- chmod 0600 /etc/postfix/*.db
- echo "Loaded 'map files'"
-else
- echo "No extra map files loaded because optional '/overrides/*.map' not provided."
-fi
-
-# Actually run Postfix
-rm -f /var/run/rsyslogd.pid
-chown -R postfix: /queue
-/usr/lib/postfix/post-install meta_directory=/etc/postfix create-missing
-/usr/lib/postfix/master &
-exec rsyslogd -n
diff --git a/rainloop/default.ini b/rainloop/default.ini
index 5c6f79bc..53545bef 100644
--- a/rainloop/default.ini
+++ b/rainloop/default.ini
@@ -1,15 +1,15 @@
-imap_host = "imap"
+imap_host = "front"
imap_port = 143
-imap_secure = "TLS"
+imap_secure = "None"
imap_short_login = Off
sieve_use = On
sieve_allow_raw = Off
sieve_host = "imap"
sieve_port = 4190
sieve_secure = "TLS"
-smtp_host = "smtp"
-smtp_port = 587
-smtp_secure = "TLS"
+smtp_host = "front"
+smtp_port = 25
+smtp_secure = "None"
smtp_short_login = Off
smtp_auth = On
smtp_php_mail = Off
diff --git a/roundcube/config.inc.php b/roundcube/config.inc.php
index 65de8617..a867a169 100644
--- a/roundcube/config.inc.php
+++ b/roundcube/config.inc.php
@@ -17,10 +17,10 @@ $config['plugins'] = array(
);
// Mail servers
-$config['default_host'] = 'tls://imap';
+$config['default_host'] = 'front';
$config['default_port'] = 143;
-$config['smtp_server'] = 'tls://smtp';
-$config['smtp_port'] = 587;
+$config['smtp_server'] = 'front';
+$config['smtp_port'] = 25;
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
diff --git a/traefik/Dockerfile b/traefik/Dockerfile
deleted file mode 100644
index efb2b364..00000000
--- a/traefik/Dockerfile
+++ /dev/null
@@ -1,8 +0,0 @@
-FROM traefik:alpine
-
-RUN apk add --no-cache bash
-
-COPY conf /conf
-COPY start.sh /start.sh
-
-CMD /start.sh
diff --git a/traefik/conf/cert.toml b/traefik/conf/cert.toml
deleted file mode 100644
index dab3cccb..00000000
--- a/traefik/conf/cert.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-defaultEntryPoints = ["http", "https"]
-logLevel = "ERROR"
-accessLogsFile = "/dev/stdout"
-
-[entryPoints]
- [entryPoints.http]
- address = ":80"
- [entryPoints.http.redirect]
- entryPoint = "https"
- [entryPoints.https]
- address = ":443"
- [entryPoints.https.tls]
- MinVersion = "VersionTLS11"
- CipherSuites = ["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"]
- [[entryPoints.https.tls.certificates]]
- CertFile = "/certs/cert.pem"
- KeyFile = "/certs/key.pem"
-
-[docker]
-endpoint = "unix:///docker.sock"
-domain = "{{ DOMAIN }}"
-watch = true
-exposedbydefault = false
-
diff --git a/traefik/conf/letsencrypt.toml b/traefik/conf/letsencrypt.toml
deleted file mode 100644
index ddc2a7b4..00000000
--- a/traefik/conf/letsencrypt.toml
+++ /dev/null
@@ -1,29 +0,0 @@
-defaultEntryPoints = ["http", "https"]
-logLevel = "ERROR"
-accessLogsFile = "/dev/stdout"
-
-[entryPoints]
- [entryPoints.http]
- address = ":80"
- [entryPoints.http.redirect]
- entryPoint = "https"
- [entryPoints.https]
- address = ":443"
- [entryPoints.https.tls]
- MinVersion = "VersionTLS11"
- CipherSuites = ["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"]
-
-[docker]
-endpoint = "unix:///docker.sock"
-domain = "{{ DOMAIN }}"
-watch = true
-exposedbydefault = false
-
-[acme]
-email = "{{ POSTMASTER }}@{{ DOMAIN }}"
-storageFile = "/certs/acme.json"
-onDemand = false
-OnHostRule = true
-entryPoint = "https"
-
-
diff --git a/traefik/conf/notls.toml b/traefik/conf/notls.toml
deleted file mode 100644
index 3226aa3f..00000000
--- a/traefik/conf/notls.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-defaultEntryPoints = ["http"]
-logLevel = "ERROR"
-accessLogsFile = "/dev/stdout"
-
-[entryPoints]
- [entryPoints.http]
- address = ":80"
-
-[docker]
-endpoint = "unix:///docker.sock"
-domain = "{{ DOMAIN }}"
-watch = true
-exposedbydefault = false
-
diff --git a/traefik/start.sh b/traefik/start.sh
deleted file mode 100755
index ee148a6d..00000000
--- a/traefik/start.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-# Substitute configuration
-for VARIABLE in `env | cut -f1 -d=`; do
- sed -i "s={{ $VARIABLE }}=${!VARIABLE}=g" /conf/*.toml
-done
-
-# Select the proper configuration
-cp /conf/$TLS_FLAVOR.toml /conf/traefik.toml
-
-exec traefik -c /conf/traefik.toml
-