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 @@ +{{ 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 -
{% 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"