diff --git a/core/admin/mailu/configuration.py b/core/admin/mailu/configuration.py index 7dcd7c3a..66b0b832 100644 --- a/core/admin/mailu/configuration.py +++ b/core/admin/mailu/configuration.py @@ -67,6 +67,7 @@ DEFAULT_CONFIG = { 'HOST_REDIS': 'redis', 'HOST_FRONT': 'front', 'SUBNET': '192.168.203.0/24', + 'SUBNET6': None, 'POD_ADDRESS_RANGE': None } diff --git a/core/admin/mailu/internal/__init__.py b/core/admin/mailu/internal/__init__.py index 95f2f782..560f4d97 100644 --- a/core/admin/mailu/internal/__init__.py +++ b/core/admin/mailu/internal/__init__.py @@ -1,23 +1,7 @@ -from mailu.limiter import RateLimitExceeded - -from mailu import utils -from flask import current_app as app - -import socket import flask internal = flask.Blueprint('internal', __name__, template_folder='templates') -@internal.app_errorhandler(RateLimitExceeded) -def rate_limit_handler(e): - response = flask.Response() - response.headers['Auth-Status'] = 'Authentication rate limit from one source exceeded' - response.headers['Auth-Error-Code'] = '451 4.3.2' - if int(flask.request.headers['Auth-Login-Attempt']) < 10: - response.headers['Auth-Wait'] = '3' - return response - - from mailu.internal.views import * diff --git a/core/admin/mailu/internal/views/auth.py b/core/admin/mailu/internal/views/auth.py index b1f37d17..825dba56 100644 --- a/core/admin/mailu/internal/views/auth.py +++ b/core/admin/mailu/internal/views/auth.py @@ -5,21 +5,31 @@ from flask import current_app as app import flask import flask_login import base64 - +import ipaddress @internal.route("/auth/email") def nginx_authentication(): """ Main authentication endpoint for Nginx email server """ - utils.limiter.check(flask.request.headers["Client-Ip"]) + limiter = utils.limiter.get_limiter(app.config["AUTH_RATELIMIT"], "auth-ip") + client_ip = flask.request.headers["Client-Ip"] + if not limiter.test(client_ip): + response = flask.Response() + response.headers['Auth-Status'] = 'Authentication rate limit from one source exceeded' + response.headers['Auth-Error-Code'] = '451 4.3.2' + if int(flask.request.headers['Auth-Login-Attempt']) < 10: + response.headers['Auth-Wait'] = '3' + return response headers = nginx.handle_authentication(flask.request.headers) response = flask.Response() for key, value in headers.items(): response.headers[key] = str(value) - if ("Auth-Status" not in headers) or (headers["Auth-Status"]!="OK"): - utils.limiter.hit(flask.request.headers["Client-Ip"]) - + if ("Auth-Status" not in headers) or (headers["Auth-Status"] != "OK"): + limit_subnet = str(app.config["AUTH_RATELIMIT_SUBNET"]) != 'False' + subnet = ipaddress.ip_network(app.config["SUBNET"]) + if limit_subnet or ipaddress.ip_address(client_ip) not in subnet: + limiter.hit(flask.request.headers["Client-Ip"]) return response diff --git a/core/admin/mailu/internal/views/dovecot.py b/core/admin/mailu/internal/views/dovecot.py index f44f59bc..9c665977 100644 --- a/core/admin/mailu/internal/views/dovecot.py +++ b/core/admin/mailu/internal/views/dovecot.py @@ -11,6 +11,8 @@ def dovecot_passdb_dict(user_email): user = models.User.query.get(user_email) or flask.abort(404) allow_nets = [] allow_nets.append(app.config["SUBNET"]) + if app.config["SUBNET6"]: + allow_nets.append(app.config["SUBNET6"]) if app.config["POD_ADDRESS_RANGE"]: allow_nets.append(app.config["POD_ADDRESS_RANGE"]) return flask.jsonify({ diff --git a/core/admin/mailu/internal/views/postfix.py b/core/admin/mailu/internal/views/postfix.py index 21a4aa91..a5507830 100644 --- a/core/admin/mailu/internal/views/postfix.py +++ b/core/admin/mailu/internal/views/postfix.py @@ -3,6 +3,7 @@ from mailu.internal import internal import flask import re +import srslib @internal.route("/postfix/domain/") @@ -36,7 +37,43 @@ def postfix_transport(email): return flask.abort(404) localpart, domain_name = models.Email.resolve_domain(email) relay = models.Relay.query.get(domain_name) or flask.abort(404) - return flask.jsonify("smtp:[{}]".format(relay.smtp)) + ret = "smtp:[{0}]".format(relay.smtp) + if ":" in relay.smtp: + split = relay.smtp.split(':') + ret = "smtp:[{0}]:{1}".format(split[0], split[1]) + return flask.jsonify(ret) + + +@internal.route("/postfix/recipient/map/") +def postfix_recipient_map(recipient): + """ Rewrite the envelope recipient if it is a valid SRS address. + + This is meant for bounces to go back to the original sender. + """ + srs = srslib.SRS(flask.current_app.config["SECRET_KEY"]) + if srslib.SRS.is_srs_address(recipient): + try: + return flask.jsonify(srs.reverse(recipient)) + except srslib.Error as error: + return flask.abort(404) + return flask.abort(404) + + +@internal.route("/postfix/sender/map/") +def postfix_sender_map(sender): + """ Rewrite the envelope sender in case the mail was not emitted by us. + + This is for bounces to come back the reverse path properly. + """ + srs = srslib.SRS(flask.current_app.config["SECRET_KEY"]) + domain = flask.current_app.config["DOMAIN"] + try: + localpart, domain_name = models.Email.resolve_domain(sender) + except Exception as error: + return flask.abort(404) + if models.Domain.query.get(domain_name): + return flask.abort(404) + return flask.jsonify(srs.forward(sender, domain)) @internal.route("/postfix/sender/login/") diff --git a/core/admin/mailu/limiter.py b/core/admin/mailu/limiter.py index f7819c31..b5f99915 100644 --- a/core/admin/mailu/limiter.py +++ b/core/admin/mailu/limiter.py @@ -1,36 +1,34 @@ import limits import limits.storage import limits.strategies -import ipaddress -class RateLimitExceeded(Exception): - pass -class Limiter: +class LimitWrapper(object): + """ Wraps a limit by providing the storage, item and identifiers + """ - def __init__(self): - self.storage = None - self.limiter = None - self.rate = None - self.subnet = None - self.rate_limit_subnet = True + def __init__(self, limiter, limit, *identifiers): + self.limiter = limiter + self.limit = limit + self.base_identifiers = identifiers + + def test(self, *args): + return self.limiter.test(self.limit, *(self.base_identifiers + args)) + + def hit(self, *args): + return self.limiter.hit(self.limit, *(self.base_identifiers + args)) + + def get_window_stats(self, *args): + return self.limiter.get_window_stats(self.limit, *(self.base_identifiers + args)) + + +class LimitWraperFactory(object): + """ Global limiter, to be used as a factory + """ def init_app(self, app): self.storage = limits.storage.storage_from_string(app.config["RATELIMIT_STORAGE_URL"]) self.limiter = limits.strategies.MovingWindowRateLimiter(self.storage) - self.rate = limits.parse(app.config["AUTH_RATELIMIT"]) - self.rate_limit_subnet = str(app.config["AUTH_RATELIMIT_SUBNET"])!='False' - self.subnet = ipaddress.ip_network(app.config["SUBNET"]) - def check(self,clientip): - # disable limits for internal requests (e.g. from webmail)? - if self.rate_limit_subnet==False and ipaddress.ip_address(clientip) in self.subnet: - return - if not self.limiter.test(self.rate,"client-ip",clientip): - raise RateLimitExceeded() - - def hit(self,clientip): - # disable limits for internal requests (e.g. from webmail)? - if self.rate_limit_subnet==False and ipaddress.ip_address(clientip) in self.subnet: - return - self.limiter.hit(self.rate,"client-ip",clientip) + def get_limiter(self, limit, *args): + return LimitWrapper(self.limiter, limits.parse(limit), *args) \ No newline at end of file diff --git a/core/admin/mailu/manage.py b/core/admin/mailu/manage.py index 819fe410..62f214d3 100644 --- a/core/admin/mailu/manage.py +++ b/core/admin/mailu/manage.py @@ -177,7 +177,7 @@ def config_update(verbose=False, delete_objects=False): """sync configuration with data from YAML-formatted stdin""" import yaml import sys - new_config = yaml.load(sys.stdin) + new_config = yaml.safe_load(sys.stdin) # print new_config domains = new_config.get('domains', []) tracked_domains = set() diff --git a/core/admin/mailu/translations/ca/LC_MESSAGES/messages.po b/core/admin/mailu/translations/ca/LC_MESSAGES/messages.po index 01ba188a..a14d7faf 100644 --- a/core/admin/mailu/translations/ca/LC_MESSAGES/messages.po +++ b/core/admin/mailu/translations/ca/LC_MESSAGES/messages.po @@ -8,13 +8,16 @@ msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2018-04-22 12:10+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"PO-Revision-Date: 2020-03-11 23:03+0000\n" +"Last-Translator: Jaume Barber \n" +"Language-Team: Catalan \n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.11.2\n" "Generated-By: Babel 2.5.3\n" #: mailu/ui/forms.py:32 @@ -22,45 +25,46 @@ msgid "Invalid email address." msgstr "" #: mailu/ui/forms.py:36 +#, fuzzy msgid "Confirm" -msgstr "" +msgstr "Confirmeu" #: mailu/ui/forms.py:40 mailu/ui/forms.py:77 msgid "E-mail" -msgstr "" +msgstr "Correu" #: mailu/ui/forms.py:41 mailu/ui/forms.py:78 mailu/ui/forms.py:90 #: mailu/ui/forms.py:109 mailu/ui/forms.py:162 #: mailu/ui/templates/client.html:32 mailu/ui/templates/client.html:59 msgid "Password" -msgstr "" +msgstr "Contrasenya" #: mailu/ui/forms.py:42 mailu/ui/templates/login.html:4 #: mailu/ui/templates/sidebar.html:111 msgid "Sign in" -msgstr "" +msgstr "Entreu" #: mailu/ui/forms.py:46 mailu/ui/forms.py:56 #: mailu/ui/templates/domain/details.html:27 #: mailu/ui/templates/domain/list.html:18 mailu/ui/templates/relay/list.html:17 msgid "Domain name" -msgstr "" +msgstr "Nom de domini" #: mailu/ui/forms.py:47 msgid "Maximum user count" -msgstr "" +msgstr "Nombre màxim d'usuaris" #: mailu/ui/forms.py:48 msgid "Maximum alias count" -msgstr "" +msgstr "Nombre màxim d'àlies" #: mailu/ui/forms.py:49 msgid "Maximum user quota" -msgstr "" +msgstr "Espai màxim per usuari" #: mailu/ui/forms.py:50 msgid "Enable sign-up" -msgstr "" +msgstr "Activeu el registre" #: mailu/ui/forms.py:51 mailu/ui/forms.py:72 mailu/ui/forms.py:83 #: mailu/ui/forms.py:128 mailu/ui/forms.py:140 @@ -68,308 +72,308 @@ msgstr "" #: mailu/ui/templates/relay/list.html:19 mailu/ui/templates/token/list.html:19 #: mailu/ui/templates/user/list.html:23 msgid "Comment" -msgstr "" +msgstr "Comentari" #: mailu/ui/forms.py:52 mailu/ui/forms.py:61 mailu/ui/forms.py:66 #: mailu/ui/forms.py:73 mailu/ui/forms.py:132 mailu/ui/forms.py:141 msgid "Create" -msgstr "" +msgstr "Creeu" #: mailu/ui/forms.py:57 msgid "Initial admin" -msgstr "" +msgstr "Admin inicial" #: mailu/ui/forms.py:58 msgid "Admin password" -msgstr "" +msgstr "Contrasenya d'admin" #: mailu/ui/forms.py:59 mailu/ui/forms.py:79 mailu/ui/forms.py:91 msgid "Confirm password" -msgstr "" +msgstr "Confirmeu la contrasenya" #: mailu/ui/forms.py:65 msgid "Alternative name" -msgstr "" +msgstr "Nom alternatiu" #: mailu/ui/forms.py:70 msgid "Relayed domain name" -msgstr "" +msgstr "Nom de domini traspassat (relayed)" #: mailu/ui/forms.py:71 mailu/ui/templates/relay/list.html:18 msgid "Remote host" -msgstr "" +msgstr "Amfitrió remot" #: mailu/ui/forms.py:80 mailu/ui/templates/user/list.html:22 #: mailu/ui/templates/user/signup_domain.html:16 msgid "Quota" -msgstr "" +msgstr "Espai" #: mailu/ui/forms.py:81 msgid "Allow IMAP access" -msgstr "" +msgstr "Permeteu accés IMAP" #: mailu/ui/forms.py:82 msgid "Allow POP3 access" -msgstr "" +msgstr "Permeteu accés POP3" #: mailu/ui/forms.py:84 msgid "Enabled" -msgstr "" +msgstr "Activat" #: mailu/ui/forms.py:85 msgid "Save" -msgstr "" +msgstr "Desa" #: mailu/ui/forms.py:89 msgid "Email address" -msgstr "" +msgstr "Adreça email" #: mailu/ui/forms.py:93 mailu/ui/templates/sidebar.html:117 #: mailu/ui/templates/user/signup.html:4 #: mailu/ui/templates/user/signup_domain.html:4 msgid "Sign up" -msgstr "" +msgstr "Registreu-vos" #: mailu/ui/forms.py:97 msgid "Displayed name" -msgstr "" +msgstr "Nom per mostrar" #: mailu/ui/forms.py:98 msgid "Enable spam filter" -msgstr "" +msgstr "Activeu filtre d'spam" #: mailu/ui/forms.py:99 msgid "Spam filter tolerance" -msgstr "" +msgstr "Tolerància del filtre spam" #: mailu/ui/forms.py:100 msgid "Enable forwarding" -msgstr "" +msgstr "Activeu el reenviament" #: mailu/ui/forms.py:101 msgid "Keep a copy of the emails" -msgstr "" +msgstr "Mantigueu una còpia dels correus" #: mailu/ui/forms.py:103 mailu/ui/forms.py:139 #: mailu/ui/templates/alias/list.html:20 msgid "Destination" -msgstr "" +msgstr "Destinació" #: mailu/ui/forms.py:105 msgid "Save settings" -msgstr "" +msgstr "Desa ajustos" #: mailu/ui/forms.py:110 msgid "Password check" -msgstr "" +msgstr "Comproveu la contrasenya" #: mailu/ui/forms.py:111 mailu/ui/templates/sidebar.html:16 msgid "Update password" -msgstr "" +msgstr "Canvieu la contrasenya" #: mailu/ui/forms.py:115 msgid "Enable automatic reply" -msgstr "" +msgstr "Activeu la resposta automàtica" #: mailu/ui/forms.py:116 msgid "Reply subject" -msgstr "" +msgstr "Tema de la resposta" #: mailu/ui/forms.py:117 msgid "Reply body" -msgstr "" +msgstr "Missatge de resposta" #: mailu/ui/forms.py:119 msgid "End of vacation" -msgstr "" +msgstr "Tornada de vacances" #: mailu/ui/forms.py:120 msgid "Update" -msgstr "" +msgstr "Actualitzeu" #: mailu/ui/forms.py:125 msgid "Your token (write it down, as it will never be displayed again)" -msgstr "" +msgstr "Token personal (apunteu-lo perquè no es mostrarà de nou)" #: mailu/ui/forms.py:130 mailu/ui/templates/token/list.html:20 msgid "Authorized IP" -msgstr "" +msgstr "IP autoritzada" #: mailu/ui/forms.py:136 msgid "Alias" -msgstr "" +msgstr "Àlies" #: mailu/ui/forms.py:138 msgid "Use SQL LIKE Syntax (e.g. for catch-all aliases)" -msgstr "" +msgstr "Feu servir sintaxi tipus SQL (ex. per a agafar tots els àlies)" #: mailu/ui/forms.py:145 msgid "Admin email" -msgstr "" +msgstr "Adreça d'admin" #: mailu/ui/forms.py:146 mailu/ui/forms.py:151 mailu/ui/forms.py:164 msgid "Submit" -msgstr "" +msgstr "Envia" #: mailu/ui/forms.py:150 msgid "Manager email" -msgstr "" +msgstr "Adreça de gestor" #: mailu/ui/forms.py:155 msgid "Protocol" -msgstr "" +msgstr "Protocol" #: mailu/ui/forms.py:158 msgid "Hostname or IP" -msgstr "" +msgstr "Nom d'amfitrio o IP" #: mailu/ui/forms.py:159 mailu/ui/templates/client.html:20 #: mailu/ui/templates/client.html:47 msgid "TCP port" -msgstr "" +msgstr "Port TCP" #: mailu/ui/forms.py:160 msgid "Enable TLS" -msgstr "" +msgstr "Activeu TLS" #: mailu/ui/forms.py:161 mailu/ui/templates/client.html:28 #: mailu/ui/templates/client.html:55 mailu/ui/templates/fetch/list.html:20 msgid "Username" -msgstr "" +msgstr "Nom d'usuari" #: mailu/ui/forms.py:163 msgid "Keep emails on the server" -msgstr "" +msgstr "Mantén els correus al servidor" #: mailu/ui/forms.py:168 msgid "Announcement subject" -msgstr "" +msgstr "Tema de l'avís" #: mailu/ui/forms.py:170 msgid "Announcement body" -msgstr "" +msgstr "Missatge de l'avís" #: mailu/ui/forms.py:172 msgid "Send" -msgstr "" +msgstr "Envia" #: mailu/ui/templates/announcement.html:4 msgid "Public announcement" -msgstr "" +msgstr "Avís públic" #: mailu/ui/templates/client.html:4 mailu/ui/templates/sidebar.html:82 msgid "Client setup" -msgstr "" +msgstr "Ajustos del client" #: mailu/ui/templates/client.html:16 mailu/ui/templates/client.html:43 msgid "Mail protocol" -msgstr "" +msgstr "Protocol de correu" #: mailu/ui/templates/client.html:24 mailu/ui/templates/client.html:51 msgid "Server name" -msgstr "" +msgstr "Nom de servidor" #: mailu/ui/templates/confirm.html:4 msgid "Confirm action" -msgstr "" +msgstr "Confirmeu acció" #: mailu/ui/templates/confirm.html:13 #, python-format msgid "You are about to %(action)s. Please confirm your action." -msgstr "" +msgstr "Esteu a punt de %(action)s. Per favor, confirmeu l'acció." #: mailu/ui/templates/docker-error.html:4 msgid "Docker error" -msgstr "" +msgstr "Error de Docker" #: mailu/ui/templates/docker-error.html:12 msgid "An error occurred while talking to the Docker server." -msgstr "" +msgstr "Hi ha hagut un error de comunicació amb el servidor Docker." #: mailu/ui/templates/login.html:8 msgid "to access the administration tools" -msgstr "" +msgstr "per accedir a les eines d'administració" #: mailu/ui/templates/sidebar.html:11 mailu/ui/templates/user/list.html:34 msgid "Settings" -msgstr "" +msgstr "Ajustos" #: mailu/ui/templates/sidebar.html:21 mailu/ui/templates/user/list.html:35 msgid "Auto-reply" -msgstr "" +msgstr "Resposta automàtica" #: mailu/ui/templates/fetch/list.html:4 mailu/ui/templates/sidebar.html:26 #: mailu/ui/templates/user/list.html:36 msgid "Fetched accounts" -msgstr "" +msgstr "Comptes trobats" #: mailu/ui/templates/sidebar.html:31 mailu/ui/templates/token/list.html:4 msgid "Authentication tokens" -msgstr "" +msgstr "Tokens d'autenticació" #: mailu/ui/templates/sidebar.html:35 msgid "Administration" -msgstr "" +msgstr "Administració" #: mailu/ui/templates/sidebar.html:44 msgid "Announcement" -msgstr "" +msgstr "Avís" #: mailu/ui/templates/sidebar.html:49 msgid "Administrators" -msgstr "" +msgstr "Administradors" #: mailu/ui/templates/sidebar.html:54 msgid "Relayed domains" -msgstr "" +msgstr "Dominis tramesos" #: mailu/ui/templates/sidebar.html:59 mailu/ui/templates/user/settings.html:15 msgid "Antispam" -msgstr "" +msgstr "Antispam" #: mailu/ui/templates/sidebar.html:66 msgid "Mail domains" -msgstr "" +msgstr "Dominis de correu" #: mailu/ui/templates/sidebar.html:72 msgid "Go to" -msgstr "" +msgstr "Aneu a" #: mailu/ui/templates/sidebar.html:76 msgid "Webmail" -msgstr "" +msgstr "Correu web" #: mailu/ui/templates/sidebar.html:87 msgid "Website" -msgstr "" +msgstr "Lloc web" #: mailu/ui/templates/sidebar.html:92 msgid "Help" -msgstr "" +msgstr "Ajuda" #: mailu/ui/templates/domain/signup.html:4 mailu/ui/templates/sidebar.html:98 msgid "Register a domain" -msgstr "" +msgstr "Registreu un domini" #: mailu/ui/templates/sidebar.html:105 msgid "Sign out" -msgstr "" +msgstr "Eixiu" #: mailu/ui/templates/working.html:4 msgid "We are still working on this feature!" -msgstr "" +msgstr "Encara estem treballant en aquesta funcionalitat!" #: mailu/ui/templates/admin/create.html:4 msgid "Add a global administrator" -msgstr "" +msgstr "Afegiu un admin global" #: mailu/ui/templates/admin/list.html:4 msgid "Global administrators" -msgstr "" +msgstr "Administradors globals" #: mailu/ui/templates/admin/list.html:9 msgid "Add administrator" -msgstr "" +msgstr "Afegiu un administrador" #: mailu/ui/templates/admin/list.html:16 mailu/ui/templates/alias/list.html:18 #: mailu/ui/templates/alternative/list.html:18 @@ -378,12 +382,12 @@ msgstr "" #: mailu/ui/templates/relay/list.html:16 mailu/ui/templates/token/list.html:18 #: mailu/ui/templates/user/list.html:18 msgid "Actions" -msgstr "" +msgstr "Accions" #: mailu/ui/templates/admin/list.html:17 mailu/ui/templates/alias/list.html:19 #: mailu/ui/templates/manager/list.html:19 mailu/ui/templates/user/list.html:20 msgid "Email" -msgstr "" +msgstr "Correu" #: mailu/ui/templates/admin/list.html:22 mailu/ui/templates/alias/list.html:29 #: mailu/ui/templates/alternative/list.html:25 @@ -392,23 +396,23 @@ msgstr "" #: mailu/ui/templates/relay/list.html:27 mailu/ui/templates/token/list.html:26 #: mailu/ui/templates/user/list.html:31 msgid "Delete" -msgstr "" +msgstr "Esborra" #: mailu/ui/templates/alias/create.html:4 msgid "Create alias" -msgstr "" +msgstr "Creeu àlies" #: mailu/ui/templates/alias/edit.html:4 msgid "Edit alias" -msgstr "" +msgstr "Editeu àlies" #: mailu/ui/templates/alias/list.html:4 msgid "Alias list" -msgstr "" +msgstr "Llista d'àlies" #: mailu/ui/templates/alias/list.html:12 msgid "Add alias" -msgstr "" +msgstr "Afegiu àlies" #: mailu/ui/templates/alias/list.html:22 #: mailu/ui/templates/alternative/list.html:20 @@ -416,118 +420,121 @@ msgstr "" #: mailu/ui/templates/relay/list.html:20 mailu/ui/templates/token/list.html:21 #: mailu/ui/templates/user/list.html:24 msgid "Created" -msgstr "" +msgstr "Creat" #: mailu/ui/templates/alias/list.html:23 mailu/ui/templates/domain/list.html:23 #: mailu/ui/templates/fetch/list.html:25 mailu/ui/templates/relay/list.html:21 #: mailu/ui/templates/user/list.html:25 msgid "Last edit" -msgstr "" +msgstr "Última edició" #: mailu/ui/templates/alias/list.html:28 mailu/ui/templates/domain/list.html:30 #: mailu/ui/templates/fetch/list.html:30 mailu/ui/templates/relay/list.html:26 #: mailu/ui/templates/user/list.html:30 msgid "Edit" -msgstr "" +msgstr "Edita" #: mailu/ui/templates/alternative/create.html:4 msgid "Create alternative domain" -msgstr "" +msgstr "Creeu domini alternatiu" #: mailu/ui/templates/alternative/list.html:4 msgid "Alternative domain list" -msgstr "" +msgstr "Llista de dominis alternatius" #: mailu/ui/templates/alternative/list.html:12 msgid "Add alternative" -msgstr "" +msgstr "Afegiu alternativa" #: mailu/ui/templates/alternative/list.html:19 msgid "Name" -msgstr "" +msgstr "Nom" #: mailu/ui/templates/domain/create.html:4 #: mailu/ui/templates/domain/list.html:9 msgid "New domain" -msgstr "" +msgstr "Nou domini" #: mailu/ui/templates/domain/details.html:4 msgid "Domain details" -msgstr "" +msgstr "Detalls del domini" #: mailu/ui/templates/domain/details.html:15 msgid "Regenerate keys" -msgstr "" +msgstr "Regenereu les claus" #: mailu/ui/templates/domain/details.html:17 msgid "Generate keys" -msgstr "" +msgstr "Genereu claus" #: mailu/ui/templates/domain/details.html:31 msgid "DNS MX entry" -msgstr "" +msgstr "Entrada DNS MX" #: mailu/ui/templates/domain/details.html:35 msgid "DNS SPF entries" -msgstr "" +msgstr "Entrada DNS SPF" #: mailu/ui/templates/domain/details.html:42 msgid "DKIM public key" -msgstr "" +msgstr "Clau pública DKIM" #: mailu/ui/templates/domain/details.html:46 msgid "DNS DKIM entry" -msgstr "" +msgstr "Entrada DNS DKIM" #: mailu/ui/templates/domain/details.html:50 msgid "DNS DMARC entry" -msgstr "" +msgstr "Entrada DNS DMARC" #: mailu/ui/templates/domain/edit.html:4 msgid "Edit domain" -msgstr "" +msgstr "Edita domini" #: mailu/ui/templates/domain/list.html:4 msgid "Domain list" -msgstr "" +msgstr "Llista de dominis" #: mailu/ui/templates/domain/list.html:17 msgid "Manage" -msgstr "" +msgstr "Gestioneu" #: mailu/ui/templates/domain/list.html:19 msgid "Mailbox count" -msgstr "" +msgstr "Nombre de bústies" #: mailu/ui/templates/domain/list.html:20 msgid "Alias count" -msgstr "" +msgstr "Nombre d'àlies" #: mailu/ui/templates/domain/list.html:28 msgid "Details" -msgstr "" +msgstr "Detalls" #: mailu/ui/templates/domain/list.html:35 msgid "Users" -msgstr "" +msgstr "Usuaris" #: mailu/ui/templates/domain/list.html:36 msgid "Aliases" -msgstr "" +msgstr "Àlies" #: mailu/ui/templates/domain/list.html:37 msgid "Managers" -msgstr "" +msgstr "Gestors" #: mailu/ui/templates/domain/list.html:39 msgid "Alternatives" -msgstr "" +msgstr "Alternatives" #: mailu/ui/templates/domain/signup.html:13 msgid "" "In order to register a new domain, you must first setup the\n" " domain zone so that the domain MX points to this server" msgstr "" +"Per a registrar un nou domini, heu de configurar la \n" +" zona de dominis per tal que el domini MX apunte a aquest " +"servidor" #: mailu/ui/templates/domain/signup.html:18 msgid "" @@ -539,131 +546,136 @@ msgid "" "cache\n" " expires." msgstr "" +"Si no sabeu configurar un registre MX a la zona DNS,\n" +"contacteu el vostre proveïdor o administrador de DNS. Per favor, espereu \n" +"uns quants minuts despres d'ajustar el registre MX perquè la " +"caixet \n" +"del servidor local expire." #: mailu/ui/templates/fetch/create.html:4 msgid "Add a fetched account" -msgstr "" +msgstr "Afegiu un compte (fetched)" #: mailu/ui/templates/fetch/edit.html:4 msgid "Update a fetched account" -msgstr "" +msgstr "Actualitzeu un compte (fetched)" #: mailu/ui/templates/fetch/list.html:12 msgid "Add an account" -msgstr "" +msgstr "Afegiu un compte" #: mailu/ui/templates/fetch/list.html:19 msgid "Endpoint" -msgstr "" +msgstr "Endpoint" #: mailu/ui/templates/fetch/list.html:21 msgid "Keep emails" -msgstr "" +msgstr "Mantingueu els correus" #: mailu/ui/templates/fetch/list.html:22 msgid "Last check" -msgstr "" +msgstr "Última comprovació" #: mailu/ui/templates/fetch/list.html:35 msgid "yes" -msgstr "" +msgstr "sí" #: mailu/ui/templates/fetch/list.html:35 msgid "no" -msgstr "" +msgstr "no" #: mailu/ui/templates/manager/create.html:4 msgid "Add a manager" -msgstr "" +msgstr "Afegiu un gestor" #: mailu/ui/templates/manager/list.html:4 msgid "Manager list" -msgstr "" +msgstr "Llista de gestors" #: mailu/ui/templates/manager/list.html:12 msgid "Add manager" -msgstr "" +msgstr "Afegiu un gestor" #: mailu/ui/templates/relay/create.html:4 msgid "New relay domain" -msgstr "" +msgstr "Nou domini traspassat (relayed)" #: mailu/ui/templates/relay/edit.html:4 msgid "Edit relayd domain" -msgstr "" +msgstr "Editeu domini traspassat (relayed)" #: mailu/ui/templates/relay/list.html:4 msgid "Relayed domain list" -msgstr "" +msgstr "Llista de dominis traspassats (relayed)" #: mailu/ui/templates/relay/list.html:9 msgid "New relayed domain" -msgstr "" +msgstr "Nou domini traspassat (relayed)" #: mailu/ui/templates/token/create.html:4 msgid "Create an authentication token" -msgstr "" +msgstr "Creeu un token d'autenticació" #: mailu/ui/templates/token/list.html:12 msgid "New token" -msgstr "" +msgstr "Nou token" #: mailu/ui/templates/user/create.html:4 msgid "New user" -msgstr "" +msgstr "Nou usuari" #: mailu/ui/templates/user/create.html:15 msgid "General" -msgstr "" +msgstr "General" #: mailu/ui/templates/user/create.html:22 msgid "Features and quotas" -msgstr "" +msgstr "Funcions i espai" #: mailu/ui/templates/user/edit.html:4 msgid "Edit user" -msgstr "" +msgstr "Edita usuari" #: mailu/ui/templates/user/forward.html:4 msgid "Forward emails" -msgstr "" +msgstr "Reenvia correus" #: mailu/ui/templates/user/list.html:4 msgid "User list" -msgstr "" +msgstr "Llista d'usuaris" #: mailu/ui/templates/user/list.html:12 msgid "Add user" -msgstr "" +msgstr "Afegiu usuari" #: mailu/ui/templates/user/list.html:19 mailu/ui/templates/user/settings.html:4 msgid "User settings" -msgstr "" +msgstr "Ajustos d'usuari" #: mailu/ui/templates/user/list.html:21 msgid "Features" -msgstr "" +msgstr "Funcions" #: mailu/ui/templates/user/password.html:4 msgid "Password update" -msgstr "" +msgstr "Canvieu la contrasenya" #: mailu/ui/templates/user/reply.html:4 msgid "Automatic reply" -msgstr "" +msgstr "Resposta automàtica" #: mailu/ui/templates/user/settings.html:22 msgid "Auto-forward" -msgstr "" +msgstr "Auto-reenviament" #: mailu/ui/templates/user/signup_domain.html:8 msgid "pick a domain for the new account" -msgstr "" +msgstr "tria un domini per al compte nou" #: mailu/ui/templates/user/signup_domain.html:14 msgid "Domain" -msgstr "" +msgstr "Domini" #: mailu/ui/templates/user/signup_domain.html:15 msgid "Available slots" -msgstr "" +msgstr "Ranures lliures" diff --git a/core/admin/mailu/translations/en/LC_MESSAGES/messages.po b/core/admin/mailu/translations/en/LC_MESSAGES/messages.po index 87f411e0..2ada20b1 100644 --- a/core/admin/mailu/translations/en/LC_MESSAGES/messages.po +++ b/core/admin/mailu/translations/en/LC_MESSAGES/messages.po @@ -8,14 +8,16 @@ msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2018-04-22 12:10+0200\n" -"PO-Revision-Date: 2016-10-02 15:02+0200\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2020-03-11 23:03+0000\n" +"Last-Translator: Jae Beojkkoch \n" +"Language-Team: English \n" "Language: en\n" -"Language-Team: en \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.11.2\n" "Generated-By: Babel 2.5.3\n" #: mailu/ui/forms.py:32 @@ -24,7 +26,7 @@ msgstr "" #: mailu/ui/forms.py:36 msgid "Confirm" -msgstr "" +msgstr "Confirm" #: mailu/ui/forms.py:40 mailu/ui/forms.py:77 msgid "E-mail" @@ -684,4 +686,3 @@ msgstr "" #~ msgid "General settings" #~ msgstr "" - diff --git a/core/admin/mailu/translations/es/LC_MESSAGES/messages.po b/core/admin/mailu/translations/es/LC_MESSAGES/messages.po index c5b0322c..94b39439 100644 --- a/core/admin/mailu/translations/es/LC_MESSAGES/messages.po +++ b/core/admin/mailu/translations/es/LC_MESSAGES/messages.po @@ -1,11 +1,16 @@ msgid "" msgstr "" +"Project-Id-Version: Mailu\n" +"PO-Revision-Date: 2020-03-11 23:03+0000\n" +"Last-Translator: Jaume Barber \n" +"Language-Team: Spanish \n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: POEditor.com\n" -"Project-Id-Version: Mailu\n" -"Language: es\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.11.2\n" #: mailu/ui/forms.py:32 msgid "Invalid email address." @@ -17,7 +22,7 @@ msgstr "Confirmar" #: mailu/ui/forms.py:40 mailu/ui/forms.py:77 msgid "E-mail" -msgstr "Dirección de Correo" +msgstr "Dirección de correo" #: mailu/ui/forms.py:41 mailu/ui/forms.py:78 mailu/ui/forms.py:90 #: mailu/ui/forms.py:109 mailu/ui/forms.py:162 @@ -34,7 +39,7 @@ msgstr "Entrar" #: mailu/ui/templates/domain/details.html:27 #: mailu/ui/templates/domain/list.html:18 mailu/ui/templates/relay/list.html:17 msgid "Domain name" -msgstr "Nmbre de dominio" +msgstr "Nombre de dominio" #: mailu/ui/forms.py:47 msgid "Maximum user count" @@ -42,7 +47,7 @@ msgstr "Máximo número de usuarios" #: mailu/ui/forms.py:48 msgid "Maximum alias count" -msgstr "Máximo número de aliases" +msgstr "Máximo número de alias" #: mailu/ui/forms.py:51 mailu/ui/forms.py:72 mailu/ui/forms.py:83 #: mailu/ui/forms.py:128 mailu/ui/forms.py:140 @@ -64,7 +69,7 @@ msgstr "Confirmar contraseña" #: mailu/ui/forms.py:80 mailu/ui/templates/user/list.html:22 #: mailu/ui/templates/user/signup_domain.html:16 msgid "Quota" -msgstr "Cuota" +msgstr "Espacio" #: mailu/ui/forms.py:81 msgid "Allow IMAP access" @@ -137,7 +142,7 @@ msgstr "Usar sintaxis SQL (p.ej. para abarcar todos los alias)" #: mailu/ui/forms.py:145 msgid "Admin email" -msgstr "Correo-e del administrador" +msgstr "Correo del administrador" #: mailu/ui/forms.py:146 mailu/ui/forms.py:151 mailu/ui/forms.py:164 msgid "Submit" @@ -145,7 +150,7 @@ msgstr "Enviar" #: mailu/ui/forms.py:150 msgid "Manager email" -msgstr "Gestor de correo" +msgstr "Correo del gestor" #: mailu/ui/forms.py:155 msgid "Protocol" @@ -175,7 +180,7 @@ msgstr "Confirmar acción" #: mailu/ui/templates/confirm.html:13 msgid "You are about to %(action)s. Please confirm your action." -msgstr "Está a punto de %(action)s. Por favor, confirme su acción. " +msgstr "Está a punto de %(action)s. Por favor, confirme su acción." #: mailu/ui/templates/docker-error.html:4 msgid "Docker error" @@ -264,7 +269,7 @@ msgstr "Ayuda" #: mailu/ui/templates/working.html:4 msgid "We are still working on this feature!" -msgstr "Aún trabajamos en esta característica!" +msgstr "Aún estamos trabajando en esta funcionalidad!" #: mailu/ui/templates/admin/create.html:4 msgid "Add a global administrator" @@ -276,7 +281,7 @@ msgstr "Administradores globales" #: mailu/ui/templates/admin/list.html:9 msgid "Add administrator" -msgstr "Añadr administrador" +msgstr "Añadir administrador" #: mailu/ui/templates/admin/list.html:16 mailu/ui/templates/alias/list.html:18 #: mailu/ui/templates/alternative/list.html:18 @@ -424,7 +429,7 @@ msgstr "Punto final" #: mailu/ui/templates/fetch/list.html:22 msgid "Last check" -msgstr "Último checkeo" +msgstr "Última comprobación" #: mailu/ui/templates/manager/create.html:4 msgid "Add a manager" @@ -516,7 +521,7 @@ msgstr "Mantener los correos" #: mailu/ui/templates/fetch/list.html:35 msgid "yes" -msgstr "si" +msgstr "sí" #: mailu/ui/templates/fetch/list.html:35 msgid "no" @@ -529,7 +534,7 @@ msgstr "Nombre alternativo" #. I assume relayed domain means the server is a relay server (hoy receive it from another machine), and relay domain means hoy silla send it todo another machine. Is it right, or opossite? #: mailu/ui/forms.py:70 msgid "Relayed domain name" -msgstr "Nombre de.dominio a recepcionar" +msgstr "Nombre de dominio a recepcionar" #: mailu/ui/forms.py:71 mailu/ui/templates/relay/list.html:18 msgid "Remote host" @@ -577,7 +582,7 @@ msgstr "Nuevo dominio externo (relayed)" #: mailu/ui/forms.py:125 msgid "Your token (write it down, as it will never be displayed again)" -msgstr "Sus llaves (token) (anótelas, ya que no se mostrarán nunca más)." +msgstr "Su token (anótelo, ya que no se mostrará nunca más)" #: mailu/ui/forms.py:130 mailu/ui/templates/token/list.html:20 msgid "Authorized IP" @@ -585,7 +590,7 @@ msgstr "IP autorizada" #: mailu/ui/templates/sidebar.html:31 mailu/ui/templates/token/list.html:4 msgid "Authentication tokens" -msgstr "Tokens (llaves) autorizados" +msgstr "Tokens de autenticación" #: mailu/ui/templates/sidebar.html:72 msgid "Go to" @@ -593,15 +598,15 @@ msgstr "Ir a" #: mailu/ui/templates/sidebar.html:76 msgid "Webmail" -msgstr "Webmail" +msgstr "Correo web" #: mailu/ui/templates/sidebar.html:87 msgid "Website" -msgstr "Web" +msgstr "Correo web" #: mailu/ui/templates/token/create.html:4 msgid "Create an authentication token" -msgstr "Crear un token (llave) de autenticación." +msgstr "Crear un token de autenticación" #: mailu/ui/templates/token/list.html:12 msgid "New token" @@ -700,4 +705,3 @@ msgstr "Dominio" #: mailu/ui/templates/user/signup_domain.html:15 msgid "Available slots" msgstr "Slots disponibles" - diff --git a/core/admin/mailu/translations/it/LC_MESSAGES/messages.po b/core/admin/mailu/translations/it/LC_MESSAGES/messages.po index 4e07a794..9ef5ac84 100644 --- a/core/admin/mailu/translations/it/LC_MESSAGES/messages.po +++ b/core/admin/mailu/translations/it/LC_MESSAGES/messages.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: Mailu\n" -"PO-Revision-Date: 2019-07-22 06:23+0000\n" -"Last-Translator: kaiyou \n" +"PO-Revision-Date: 2020-03-11 23:03+0000\n" +"Last-Translator: Jaume Barber \n" "Language-Team: Italian \n" "Language: it\n" @@ -10,7 +10,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.3\n" +"X-Generator: Weblate 3.11.2\n" #: mailu/ui/forms.py:32 msgid "Invalid email address." @@ -43,11 +43,11 @@ msgstr "Nome dominio" #: mailu/ui/forms.py:47 msgid "Maximum user count" -msgstr "" +msgstr "Numero massimo utenti" #: mailu/ui/forms.py:48 msgid "Maximum alias count" -msgstr "" +msgstr "Numero massimo alias" #: mailu/ui/forms.py:51 mailu/ui/forms.py:72 mailu/ui/forms.py:83 #: mailu/ui/forms.py:128 mailu/ui/forms.py:140 @@ -55,7 +55,7 @@ msgstr "" #: mailu/ui/templates/relay/list.html:19 mailu/ui/templates/token/list.html:19 #: mailu/ui/templates/user/list.html:23 msgid "Comment" -msgstr "" +msgstr "Commento" #: mailu/ui/forms.py:52 mailu/ui/forms.py:61 mailu/ui/forms.py:66 #: mailu/ui/forms.py:73 mailu/ui/forms.py:132 mailu/ui/forms.py:141 @@ -101,7 +101,7 @@ msgstr "Salva impostazioni" #: mailu/ui/forms.py:110 msgid "Password check" -msgstr "" +msgstr "Verifica la password" #: mailu/ui/forms.py:111 mailu/ui/templates/sidebar.html:16 msgid "Update password" @@ -172,7 +172,7 @@ msgstr "Abilita TLS" #: mailu/ui/forms.py:161 mailu/ui/templates/client.html:28 #: mailu/ui/templates/client.html:55 mailu/ui/templates/fetch/list.html:20 msgid "Username" -msgstr "Username" +msgstr "Nome utente" #: mailu/ui/templates/confirm.html:4 msgid "Confirm action" @@ -188,7 +188,7 @@ msgstr "Errore Docker" #: mailu/ui/templates/docker-error.html:12 msgid "An error occurred while talking to the Docker server." -msgstr "" +msgstr "C'è stato un errore nel tentativo di connessione con il Docker server." #: mailu/admin/templates/login.html:6 msgid "Your account" @@ -196,15 +196,15 @@ msgstr "Il tuo account" #: mailu/ui/templates/login.html:8 msgid "to access the administration tools" -msgstr "" +msgstr "per accedere le impostazioni d'admin" #: mailu/ui/templates/services.html:4 mailu/ui/templates/sidebar.html:39 msgid "Services status" -msgstr "" +msgstr "Status dei servizi" #: mailu/ui/templates/services.html:10 msgid "Service" -msgstr "" +msgstr "Servizio" #: mailu/ui/templates/fetch/list.html:23 mailu/ui/templates/services.html:11 msgid "Status" @@ -245,7 +245,7 @@ msgstr "Auto-risponditore" #: mailu/ui/templates/fetch/list.html:4 mailu/ui/templates/sidebar.html:26 #: mailu/ui/templates/user/list.html:36 msgid "Fetched accounts" -msgstr "" +msgstr "Conti ricuperati" #: mailu/ui/templates/sidebar.html:105 msgid "Sign out" @@ -357,23 +357,23 @@ msgstr "Rigenera chiavi" #: mailu/ui/templates/domain/details.html:31 msgid "DNS MX entry" -msgstr "" +msgstr "Entrate DNS MX" #: mailu/ui/templates/domain/details.html:35 msgid "DNS SPF entries" -msgstr "" +msgstr "Entrate DNS SPF" #: mailu/ui/templates/domain/details.html:42 msgid "DKIM public key" -msgstr "" +msgstr "Chiave pubblica DKIM" #: mailu/ui/templates/domain/details.html:46 msgid "DNS DKIM entry" -msgstr "" +msgstr "Entrata DNS DKIM" #: mailu/ui/templates/domain/details.html:50 msgid "DNS DMARC entry" -msgstr "" +msgstr "Entrata DNS DMARC" #: mailu/ui/templates/domain/edit.html:4 msgid "Edit domain" @@ -413,11 +413,11 @@ msgstr "Manager" #: mailu/ui/templates/fetch/create.html:4 msgid "Add a fetched account" -msgstr "" +msgstr "Aggiungere un conto ricuperato" #: mailu/ui/templates/fetch/edit.html:4 msgid "Update a fetched account" -msgstr "" +msgstr "Aggiornare un conto ricuperato" #: mailu/ui/templates/fetch/list.html:12 msgid "Add an account" @@ -425,7 +425,7 @@ msgstr "Aggiungi un account" #: mailu/ui/templates/fetch/list.html:19 msgid "Endpoint" -msgstr "" +msgstr "Endpoint" #: mailu/ui/templates/fetch/list.html:22 msgid "Last check" @@ -437,7 +437,7 @@ msgstr "Aggiungi un manager" #: mailu/ui/templates/manager/list.html:4 msgid "Manager list" -msgstr "" +msgstr "Elenco di Manager" #: mailu/ui/templates/manager/list.html:12 msgid "Add manager" @@ -445,7 +445,7 @@ msgstr "Aggiungi manager" #: mailu/ui/forms.py:168 msgid "Announcement subject" -msgstr "" +msgstr "Oggetto dell'avviso" #: mailu/ui/forms.py:170 msgid "Announcement body" @@ -505,7 +505,7 @@ msgstr "Risposta automatica" #: mailu/ui/forms.py:49 msgid "Maximum user quota" -msgstr "" +msgstr "Spazio massimo per utente" #: mailu/ui/forms.py:101 msgid "Keep a copy of the emails" @@ -533,7 +533,7 @@ msgstr "Nome alternativo" #: mailu/ui/forms.py:70 msgid "Relayed domain name" -msgstr "" +msgstr "Nome di dominio affidato" #: mailu/ui/forms.py:71 mailu/ui/templates/relay/list.html:18 msgid "Remote host" @@ -541,15 +541,15 @@ msgstr "Host remoto" #: mailu/ui/templates/sidebar.html:54 msgid "Relayed domains" -msgstr "" +msgstr "Domini affidati" #: mailu/ui/templates/alternative/create.html:4 msgid "Create alternative domain" -msgstr "" +msgstr "Creare un dominio alternativo" #: mailu/ui/templates/alternative/list.html:4 msgid "Alternative domain list" -msgstr "" +msgstr "Elenco di domini alternativi" #: mailu/ui/templates/alternative/list.html:12 msgid "Add alternative" @@ -565,23 +565,23 @@ msgstr "Alternative" #: mailu/ui/templates/relay/create.html:4 msgid "New relay domain" -msgstr "" +msgstr "Nuovo dominio affidato" #: mailu/ui/templates/relay/edit.html:4 msgid "Edit relayd domain" -msgstr "" +msgstr "Editare dominio affidato" #: mailu/ui/templates/relay/list.html:4 msgid "Relayed domain list" -msgstr "" +msgstr "Elenco di domini affidati" #: mailu/ui/templates/relay/list.html:9 msgid "New relayed domain" -msgstr "" +msgstr "Nuovo dominio affidato" #: mailu/ui/forms.py:125 msgid "Your token (write it down, as it will never be displayed again)" -msgstr "" +msgstr "Il suo token (dovrà annotarlo, dato che non verrà più mostrato)" #: mailu/ui/forms.py:130 mailu/ui/templates/token/list.html:20 msgid "Authorized IP" @@ -633,58 +633,61 @@ msgstr "Tolleranza filtro spam" #: mailu/ui/forms.py:50 msgid "Enable sign-up" -msgstr "" +msgstr "Avviare l'iscrizione" #: mailu/ui/forms.py:57 msgid "Initial admin" -msgstr "" +msgstr "Admin iniziale" #: mailu/ui/forms.py:58 msgid "Admin password" -msgstr "" +msgstr "Admin password" #: mailu/ui/forms.py:84 msgid "Enabled" -msgstr "" +msgstr "Attivo" #: mailu/ui/forms.py:89 msgid "Email address" -msgstr "" +msgstr "Indirizzo email" #: mailu/ui/forms.py:93 mailu/ui/templates/sidebar.html:117 #: mailu/ui/templates/user/signup.html:4 #: mailu/ui/templates/user/signup_domain.html:4 msgid "Sign up" -msgstr "" +msgstr "Iscriversi" #: mailu/ui/forms.py:119 msgid "End of vacation" -msgstr "" +msgstr "Rientro delle vacanze" #: mailu/ui/templates/client.html:4 mailu/ui/templates/sidebar.html:82 msgid "Client setup" -msgstr "" +msgstr "Impostazioni del cliente" #: mailu/ui/templates/client.html:16 mailu/ui/templates/client.html:43 msgid "Mail protocol" -msgstr "" +msgstr "Protocolo mail" #: mailu/ui/templates/client.html:24 mailu/ui/templates/client.html:51 msgid "Server name" -msgstr "" +msgstr "Nome del server" #: mailu/ui/templates/domain/signup.html:4 mailu/ui/templates/sidebar.html:98 msgid "Register a domain" -msgstr "" +msgstr "Registrare un dominio" #: mailu/ui/templates/domain/details.html:17 msgid "Generate keys" -msgstr "" +msgstr "Generare chiavi" #: mailu/ui/templates/domain/signup.html:13 msgid "In order to register a new domain, you must first setup the\n" " domain zone so that the domain MX points to this server" msgstr "" +"Per registrare un nuovo dominio, dovrà aggiustare prima la \n" +"domain zone affinché il vostro dominio MX punti contro il " +"server" #: mailu/ui/templates/domain/signup.html:18 msgid "If you do not know how to setup an MX record for your DNS zone,\n" @@ -692,15 +695,22 @@ msgid "If you do not know how to setup an MX record for your DNS zo " couple minutes after the MX is set so the local server cache\n" " expires." msgstr "" +"Se non sa come aggiungere un registro MX alla vostra zona DNS, " +"\n" +"dovrà contattare il suo provider o amministratore DNS. Prego, attenda " +"qualche\n" +"minuto tra l'impostazione del registro MX finché la cache " +"locale \n" +"del server scaderà." #: mailu/ui/templates/user/signup_domain.html:8 msgid "pick a domain for the new account" -msgstr "" +msgstr "scelga un dominio per il nuovo conto" #: mailu/ui/templates/user/signup_domain.html:14 msgid "Domain" -msgstr "" +msgstr "Dominio" #: mailu/ui/templates/user/signup_domain.html:15 msgid "Available slots" -msgstr "" +msgstr "Slot disponibili" diff --git a/core/admin/mailu/translations/pl/LC_MESSAGES/messages.po b/core/admin/mailu/translations/pl/LC_MESSAGES/messages.po index 595b1b43..cec7a4a0 100644 --- a/core/admin/mailu/translations/pl/LC_MESSAGES/messages.po +++ b/core/admin/mailu/translations/pl/LC_MESSAGES/messages.po @@ -1,11 +1,17 @@ msgid "" msgstr "" +"Project-Id-Version: Mailu\n" +"PO-Revision-Date: 2020-02-17 20:23+0000\n" +"Last-Translator: NeroPcStation \n" +"Language-Team: Polish \n" +"Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: POEditor.com\n" -"Project-Id-Version: Mailu\n" -"Language: pl\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 3.3\n" #: mailu/ui/forms.py:32 msgid "Invalid email address." @@ -65,7 +71,7 @@ msgstr "Potwierdź hasło" #: mailu/ui/forms.py:80 mailu/ui/templates/user/list.html:22 #: mailu/ui/templates/user/signup_domain.html:16 msgid "Quota" -msgstr "" +msgstr "Maksymalna przestrzeń na dysku" #: mailu/ui/forms.py:81 msgid "Allow IMAP access" @@ -101,7 +107,7 @@ msgstr "" #: mailu/ui/forms.py:111 mailu/ui/templates/sidebar.html:16 msgid "Update password" -msgstr "Zmień hasło" +msgstr "Zaktualizuj hasło" #: mailu/ui/forms.py:100 msgid "Enable forwarding" @@ -146,7 +152,7 @@ msgstr "Prześlij" #: mailu/ui/forms.py:150 msgid "Manager email" -msgstr "" +msgstr "E-mail menedżera" #: mailu/ui/forms.py:155 msgid "Protocol" @@ -192,7 +198,7 @@ msgstr "Twoje konto" #: mailu/ui/templates/login.html:8 msgid "to access the administration tools" -msgstr "" +msgstr "aby uzyskać dostęp do narzędzi administracyjnych" #: mailu/ui/templates/services.html:4 mailu/ui/templates/sidebar.html:39 msgid "Services status" @@ -212,7 +218,7 @@ msgstr "PID" #: mailu/ui/templates/services.html:13 msgid "Image" -msgstr "" +msgstr "Obraz" #: mailu/ui/templates/services.html:14 msgid "Started" @@ -265,7 +271,7 @@ msgstr "Pomoc" #: mailu/ui/templates/working.html:4 msgid "We are still working on this feature!" -msgstr "" +msgstr "Nadal pracujemy nad tą funkcją!" #: mailu/ui/templates/admin/create.html:4 msgid "Add a global administrator" @@ -405,7 +411,7 @@ msgstr "Aliasy" #: mailu/ui/templates/domain/list.html:37 msgid "Managers" -msgstr "" +msgstr "Menedżerowie" #: mailu/ui/templates/fetch/create.html:4 msgid "Add a fetched account" @@ -425,19 +431,19 @@ msgstr "" #: mailu/ui/templates/fetch/list.html:22 msgid "Last check" -msgstr "" +msgstr "Ostatnie sprawdzenie" #: mailu/ui/templates/manager/create.html:4 msgid "Add a manager" -msgstr "" +msgstr "Dodaj menedżera" #: mailu/ui/templates/manager/list.html:4 msgid "Manager list" -msgstr "" +msgstr "Lista menedżerów" #: mailu/ui/templates/manager/list.html:12 msgid "Add manager" -msgstr "" +msgstr "Dodaj menedżera" #: mailu/ui/forms.py:168 msgid "Announcement subject" @@ -489,7 +495,7 @@ msgstr "Ustawienia użytkownika" #: mailu/ui/templates/user/list.html:21 msgid "Features" -msgstr "" +msgstr "Funkcje" #: mailu/ui/templates/user/password.html:4 msgid "Password update" @@ -501,7 +507,7 @@ msgstr "Automatyczna odpowiedź" #: mailu/ui/forms.py:49 msgid "Maximum user quota" -msgstr "" +msgstr "Maksymalny przydział użytkownika" #: mailu/ui/forms.py:101 msgid "Keep a copy of the emails" @@ -525,7 +531,7 @@ msgstr "Nie" #: mailu/ui/forms.py:65 msgid "Alternative name" -msgstr "" +msgstr "Alternatywna nazwa" #: mailu/ui/forms.py:70 msgid "Relayed domain name" @@ -533,7 +539,7 @@ msgstr "" #: mailu/ui/forms.py:71 mailu/ui/templates/relay/list.html:18 msgid "Remote host" -msgstr "" +msgstr "Zdalny host" #: mailu/ui/templates/sidebar.html:54 msgid "Relayed domains" @@ -541,19 +547,19 @@ msgstr "" #: mailu/ui/templates/alternative/create.html:4 msgid "Create alternative domain" -msgstr "" +msgstr "Utwórz alternatywną domenę" #: mailu/ui/templates/alternative/list.html:4 msgid "Alternative domain list" -msgstr "" +msgstr "Alternatywna lista domen" #: mailu/ui/templates/alternative/list.html:12 msgid "Add alternative" -msgstr "" +msgstr "Dodaj alternatywę" #: mailu/ui/templates/alternative/list.html:19 msgid "Name" -msgstr "" +msgstr "Nazwa" #: mailu/ui/templates/domain/list.html:39 msgid "Alternatives" @@ -577,19 +583,19 @@ msgstr "" #: mailu/ui/forms.py:125 msgid "Your token (write it down, as it will never be displayed again)" -msgstr "" +msgstr "Twój token (zapisz go, ponieważ nigdy więcej nie będzie wyświetlany)" #: mailu/ui/forms.py:130 mailu/ui/templates/token/list.html:20 msgid "Authorized IP" -msgstr "" +msgstr "Autoryzowany adres IP" #: mailu/ui/templates/sidebar.html:31 mailu/ui/templates/token/list.html:4 msgid "Authentication tokens" -msgstr "" +msgstr "Tokeny uwierzytelnienia" #: mailu/ui/templates/sidebar.html:72 msgid "Go to" -msgstr "" +msgstr "Przejdź do" #: mailu/ui/templates/sidebar.html:76 msgid "Webmail" @@ -601,7 +607,7 @@ msgstr "Strona internetowa" #: mailu/ui/templates/token/create.html:4 msgid "Create an authentication token" -msgstr "" +msgstr "Utwórz token uwierzytelniający" #: mailu/ui/templates/token/list.html:12 msgid "New token" @@ -625,7 +631,7 @@ msgstr "Filtr antyspamowy" #: mailu/ui/forms.py:99 msgid "Spam filter tolerance" -msgstr "" +msgstr "Tolerancja filtra spamu" #: mailu/ui/forms.py:50 msgid "Enable sign-up" @@ -633,7 +639,7 @@ msgstr "Włącz rejestrację" #: mailu/ui/forms.py:57 msgid "Initial admin" -msgstr "" +msgstr "Początkowy administrator" #: mailu/ui/forms.py:58 msgid "Admin password" @@ -641,11 +647,11 @@ msgstr "hasło administratora" #: mailu/ui/forms.py:84 msgid "Enabled" -msgstr "" +msgstr "Włączone" #: mailu/ui/forms.py:89 msgid "Email address" -msgstr "" +msgstr "Adres e-mail" #: mailu/ui/forms.py:93 mailu/ui/templates/sidebar.html:117 #: mailu/ui/templates/user/signup.html:4 @@ -655,11 +661,11 @@ msgstr "" #: mailu/ui/forms.py:119 msgid "End of vacation" -msgstr "" +msgstr "Koniec wakacji" #: mailu/ui/templates/client.html:4 mailu/ui/templates/sidebar.html:82 msgid "Client setup" -msgstr "" +msgstr "Konfiguracja klienta" #: mailu/ui/templates/client.html:16 mailu/ui/templates/client.html:43 msgid "Mail protocol" @@ -681,6 +687,8 @@ msgstr "Wygeneruj klucze" msgid "In order to register a new domain, you must first setup the\n" " domain zone so that the domain MX points to this server" msgstr "" +"Aby zarejestrować nową domenę, musisz najpierw skonfigurować strefę domeny, " +"aby domena MX wskazywała na ten serwer" #: mailu/ui/templates/domain/signup.html:18 msgid "If you do not know how to setup an MX record for your DNS zone,\n" @@ -688,10 +696,15 @@ msgid "If you do not know how to setup an MX record for your DNS zo " couple minutes after the MX is set so the local server cache\n" " expires." msgstr "" +"Jeśli nie wiesz, jak skonfigurować rekord MX dla swojej " +"strefy DNS,\n" +"skontaktuj się z dostawcą DNS lub administratorem. Proszę również poczekać\n" +"kilka minut po ustawieniu MX , żeby pamięć podręczna serwera " +"lokalnego wygasła." #: mailu/ui/templates/user/signup_domain.html:8 msgid "pick a domain for the new account" -msgstr "" +msgstr "wybierz domenę dla nowego konta" #: mailu/ui/templates/user/signup_domain.html:14 msgid "Domain" @@ -699,5 +712,4 @@ msgstr "Domena" #: mailu/ui/templates/user/signup_domain.html:15 msgid "Available slots" -msgstr "" - +msgstr "Dostępne miejsca" diff --git a/core/admin/mailu/utils.py b/core/admin/mailu/utils.py index df23b8e7..39181678 100644 --- a/core/admin/mailu/utils.py +++ b/core/admin/mailu/utils.py @@ -20,7 +20,7 @@ def handle_needs_login(): ) # Rate limiter -limiter = limiter.Limiter() +limiter = limiter.LimitWraperFactory() # Application translation babel = flask_babel.Babel() diff --git a/core/admin/requirements-prod.txt b/core/admin/requirements-prod.txt index e61eebfd..e04089c4 100644 --- a/core/admin/requirements-prod.txt +++ b/core/admin/requirements-prod.txt @@ -41,9 +41,10 @@ redis==3.2.1 six==1.12.0 socrate==0.1.1 SQLAlchemy==1.3.3 +srslib==0.1.4 tabulate==0.8.3 tenacity==5.0.4 -validators==0.12.5 +validators==0.12.6 visitor==0.1.3 Werkzeug==0.15.3 WTForms==2.2.1 diff --git a/core/admin/requirements.txt b/core/admin/requirements.txt index bc6e772f..9739ed3f 100644 --- a/core/admin/requirements.txt +++ b/core/admin/requirements.txt @@ -22,3 +22,4 @@ tenacity mysqlclient psycopg2 idna +srslib diff --git a/core/dovecot/Dockerfile b/core/dovecot/Dockerfile index bb67370c..da75140c 100644 --- a/core/dovecot/Dockerfile +++ b/core/dovecot/Dockerfile @@ -1,4 +1,15 @@ ARG DISTRO=alpine:3.10 +FROM $DISTRO as builder +WORKDIR /tmp +RUN apk add git build-base automake autoconf libtool dovecot-dev xapian-core-dev icu-dev +RUN git clone https://github.com/grosjo/fts-xapian.git \ + && cd fts-xapian \ + && git checkout 1.2.7 \ + && autoreconf -vi \ + && PANDOC=false ./configure --with-dovecot=/usr/lib/dovecot \ + && make \ + && make install + FROM $DISTRO # python3 shared with most images RUN apk add --no-cache \ @@ -13,9 +24,11 @@ RUN pip3 install "podop>0.2.5" # Image specific layers under this line RUN apk add --no-cache \ - dovecot dovecot-lmtpd dovecot-pop3d dovecot-submissiond dovecot-pigeonhole-plugin rspamd-client \ + dovecot dovecot-lmtpd dovecot-pop3d dovecot-submissiond dovecot-pigeonhole-plugin rspamd-client xapian-core \ && mkdir /var/lib/dovecot +COPY --from=builder /usr/lib/dovecot/lib21_fts_xapian_plugin.* /usr/lib/dovecot/ + COPY conf /conf COPY start.py /start.py diff --git a/core/dovecot/conf/dovecot.conf b/core/dovecot/conf/dovecot.conf index f4181e0c..aa33a7bb 100644 --- a/core/dovecot/conf/dovecot.conf +++ b/core/dovecot/conf/dovecot.conf @@ -21,7 +21,8 @@ mail_access_groups = mail maildir_stat_dirs = yes mailbox_list_index = yes mail_vsize_bg_after_count = 100 -mail_plugins = $mail_plugins quota quota_clone zlib +mail_plugins = $mail_plugins quota quota_clone zlib fts fts_xapian +default_vsz_limit = 2GB namespace inbox { inbox = yes @@ -38,6 +39,12 @@ plugin { quota_vsizes = yes quota_clone_dict = proxy:/tmp/podop.socket:quota + fts = xapian + fts_xapian = partial=2 full=30 + fts_autoindex = yes + fts_enforced = yes + fts_autoindex_exclude = \Trash + {% if COMPRESSION in [ 'gz', 'bz2' ] %} zlib_save = {{ COMPRESSION }} {% endif %} diff --git a/core/nginx/conf/nginx.conf b/core/nginx/conf/nginx.conf index a8228888..250ceec7 100644 --- a/core/nginx/conf/nginx.conf +++ b/core/nginx/conf/nginx.conf @@ -218,8 +218,9 @@ mail { listen 25; listen [::]:25; {% if TLS and not TLS_ERROR %} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA; + ssl_prefer_server_ciphers on; starttls on; {% endif %} protocol smtp; diff --git a/core/nginx/conf/tls.conf b/core/nginx/conf/tls.conf index e1639256..5d7ec031 100644 --- a/core/nginx/conf/tls.conf +++ b/core/nginx/conf/tls.conf @@ -1,8 +1,8 @@ -ssl_protocols TLSv1.1 TLSv1.2; -ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384'; -ssl_prefer_server_ciphers on; -ssl_session_timeout 10m; -ssl_session_tickets off; ssl_certificate {{ TLS[0] }}; ssl_certificate_key {{ TLS[1] }}; +ssl_session_timeout 1d; +ssl_session_tickets off; ssl_dhparam /conf/dhparam.pem; +ssl_protocols TLSv1.2 TLSv1.3; +ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; +ssl_prefer_server_ciphers off; diff --git a/core/postfix/conf/main.cf b/core/postfix/conf/main.cf index 0790946d..8b4b11ac 100644 --- a/core/postfix/conf/main.cf +++ b/core/postfix/conf/main.cf @@ -75,6 +75,12 @@ relay_domains = ${podop}transport transport_maps = ${podop}transport virtual_transport = lmtp:inet:{{ LMTP_ADDRESS }} +# Sender and recipient canonical maps, mostly for SRS +sender_canonical_maps = ${podop}sendermap +sender_canonical_classes = envelope_sender +recipient_canonical_maps = ${podop}recipientmap +recipient_canonical_classes= envelope_recipient,header_recipient + # In order to prevent Postfix from running DNS query, enforce the use of the # native DNS stack, that will check /etc/hosts properly. lmtp_host_lookup = native @@ -120,4 +126,3 @@ milter_default_action = tempfail ############### # Extra Settings ############### - diff --git a/core/postfix/start.py b/core/postfix/start.py index 7523bb4d..c32099bf 100755 --- a/core/postfix/start.py +++ b/core/postfix/start.py @@ -21,10 +21,16 @@ def start_podop(): ("alias", "url", url + "alias/§"), ("domain", "url", url + "domain/§"), ("mailbox", "url", url + "mailbox/§"), + ("recipientmap", "url", url + "recipient/map/§"), + ("sendermap", "url", url + "sender/map/§"), ("senderaccess", "url", url + "sender/access/§"), ("senderlogin", "url", url + "sender/login/§") ]) +def is_valid_postconf_line(line): + return not line.startswith("#") \ + and not line == '' + # Actual startup script os.environ["FRONT_ADDRESS"] = system.get_host_address_from_environment("FRONT", "front") os.environ["ADMIN_ADDRESS"] = system.get_host_address_from_environment("ADMIN", "admin") @@ -36,11 +42,13 @@ for postfix_file in glob.glob("/conf/*.cf"): if os.path.exists("/overrides/postfix.cf"): for line in open("/overrides/postfix.cf").read().strip().split("\n"): - os.system('postconf -e "{}"'.format(line)) + if is_valid_postconf_line(line): + os.system('postconf -e "{}"'.format(line)) if os.path.exists("/overrides/postfix.master"): for line in open("/overrides/postfix.master").read().strip().split("\n"): - os.system('postconf -Me "{}"'.format(line)) + if is_valid_postconf_line(line): + os.system('postconf -Me "{}"'.format(line)) for map_file in glob.glob("/overrides/*.map"): destination = os.path.join("/etc/postfix", os.path.basename(map_file)) diff --git a/docs/compose/.env b/docs/compose/.env index 218b94d2..69c91d82 100644 --- a/docs/compose/.env +++ b/docs/compose/.env @@ -38,7 +38,7 @@ POSTMASTER=admin TLS_FLAVOR=cert # Authentication rate limit (per source IP address) -AUTH_RATELIMIT=10/minute;1000/hour +AUTH_RATELIMIT=10/minute # Opt-out of statistics, replace with "True" to opt out DISABLE_STATISTICS=False @@ -68,6 +68,10 @@ ANTIVIRUS=none # Max attachment size will be 33% smaller MESSAGE_SIZE_LIMIT=50000000 +# Message rate limit for outgoing messages +# This limit is per user +MESSAGE_RATELIMIT=100/day + # Networks granted relay permissions # Use this with care, all hosts in this networks will be able to send mail without authentication! RELAYNETS= diff --git a/docs/configuration.rst b/docs/configuration.rst index cda6becb..2b7227ba 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -46,7 +46,6 @@ rules does also apply to auth requests coming from ``SUBNET``, especially for th If you disable this, ensure that the rate limit on the webmail is enforced in a different way (e.g. roundcube plug-in), otherwise an attacker can simply bypass the limit using webmail. - The ``TLS_FLAVOR`` sets how Mailu handles TLS connections. Setting this value to ``notls`` will cause Mailu not to server any web content! More on :ref:`tls_flavor`. @@ -57,6 +56,10 @@ The ``MESSAGE_SIZE_LIMIT`` is the maximum size of a single email. It should not be too low to avoid dropping legitimate emails and should not be too high to avoid filling the disks with large junk emails. +The ``MESSAGE_RATELIMIT`` is the limit of messages a single user can send. This is +meant to fight outbound spam in case of compromised or malicious account on the +server. + The ``RELAYNETS`` are network addresses for which mail is relayed for free with no authentication required. This should be used with great care. If you want other Docker services' outbound mail to be relayed, you can set this to ``172.16.0.0/12`` diff --git a/docs/faq.rst b/docs/faq.rst index b141531e..38cf467b 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -456,7 +456,7 @@ follow these steps: logging: driver: journald -2. Add the /etc/fail2ban/jail.d/bad-auth.conf +2. Add the /etc/fail2ban/filter.d/bad-auth.conf .. code-block:: bash diff --git a/docs/kubernetes/mailu/imap.yaml b/docs/kubernetes/mailu/imap.yaml index c3a188c7..64e69930 100644 --- a/docs/kubernetes/mailu/imap.yaml +++ b/docs/kubernetes/mailu/imap.yaml @@ -67,7 +67,6 @@ spec: role: mail tier: backend ports: - ports: - name: imap-auth port: 2102 protocol: TCP diff --git a/optional/fetchmail/fetchmail.py b/optional/fetchmail/fetchmail.py index f3ee6a70..fb0c6f04 100755 --- a/optional/fetchmail/fetchmail.py +++ b/optional/fetchmail/fetchmail.py @@ -8,6 +8,7 @@ import subprocess import re import requests import sys +import traceback FETCHMAIL = """ @@ -45,47 +46,50 @@ def fetchmail(fetchmailrc): def run(debug): - fetches = requests.get("http://admin/internal/fetch").json() - smtphost, smtpport = extract_host_port(os.environ.get("HOST_SMTP", "smtp"), None) - if smtpport is None: - smtphostport = smtphost - else: - smtphostport = "%s/%d" % (smtphost, smtpport) - for fetch in fetches: - fetchmailrc = "" - options = "options antispam 501, 504, 550, 553, 554" - options += " sslmode wrapped" if fetch["tls"] else "" - options += " keep" if fetch["keep"] else " fetchall" - fetchmailrc += RC_LINE.format( - user_email=escape_rc_string(fetch["user_email"]), - protocol=fetch["protocol"], - host=escape_rc_string(fetch["host"]), - port=fetch["port"], - smtphost=smtphostport, - username=escape_rc_string(fetch["username"]), - password=escape_rc_string(fetch["password"]), - options=options - ) - if debug: - print(fetchmailrc) - try: - print(fetchmail(fetchmailrc)) - error_message = "" - except subprocess.CalledProcessError as error: - error_message = error.output.decode("utf8") - # No mail is not an error - if not error_message.startswith("fetchmail: No mail"): - print(error_message) - user_info = "for %s at %s" % (fetch["user_email"], fetch["host"]) - # Number of messages seen is not a error as well - if ("messages" in error_message and - "(seen " in error_message and - user_info in error_message): - print(error_message) - finally: - requests.post("http://admin/internal/fetch/{}".format(fetch["id"]), - json=error_message.split("\n")[0] + try: + fetches = requests.get("http://admin/internal/fetch").json() + smtphost, smtpport = extract_host_port(os.environ.get("HOST_SMTP", "smtp"), None) + if smtpport is None: + smtphostport = smtphost + else: + smtphostport = "%s/%d" % (smtphost, smtpport) + for fetch in fetches: + fetchmailrc = "" + options = "options antispam 501, 504, 550, 553, 554" + options += " sslmode wrapped" if fetch["tls"] else "" + options += " keep" if fetch["keep"] else " fetchall" + fetchmailrc += RC_LINE.format( + user_email=escape_rc_string(fetch["user_email"]), + protocol=fetch["protocol"], + host=escape_rc_string(fetch["host"]), + port=fetch["port"], + smtphost=smtphostport, + username=escape_rc_string(fetch["username"]), + password=escape_rc_string(fetch["password"]), + options=options ) + if debug: + print(fetchmailrc) + try: + print(fetchmail(fetchmailrc)) + error_message = "" + except subprocess.CalledProcessError as error: + error_message = error.output.decode("utf8") + # No mail is not an error + if not error_message.startswith("fetchmail: No mail"): + print(error_message) + user_info = "for %s at %s" % (fetch["user_email"], fetch["host"]) + # Number of messages seen is not a error as well + if ("messages" in error_message and + "(seen " in error_message and + user_info in error_message): + print(error_message) + finally: + requests.post("http://admin/internal/fetch/{}".format(fetch["id"]), + json=error_message.split("\n")[0] + ) + except Exception: + traceback.print_exc() if __name__ == "__main__": diff --git a/setup/flavors/compose/mailu.env b/setup/flavors/compose/mailu.env index 180239c3..78ecce72 100644 --- a/setup/flavors/compose/mailu.env +++ b/setup/flavors/compose/mailu.env @@ -30,8 +30,8 @@ POSTMASTER={{ postmaster }} TLS_FLAVOR={{ tls_flavor }} # Authentication rate limit (per source IP address) -{% if auth_ratelimit_pm > '0' and auth_ratelimit_ph > '0' %} -AUTH_RATELIMIT={{ auth_ratelimit_pm }}/minute;{{ auth_ratelimit_ph }}/hour +{% if auth_ratelimit_pm > '0' %} +AUTH_RATELIMIT={{ auth_ratelimit_pm }}/minute {% endif %} # Opt-out of statistics, replace with "True" to opt out diff --git a/setup/templates/steps/config.html b/setup/templates/steps/config.html index 330e008f..b3e57e22 100644 --- a/setup/templates/steps/config.html +++ b/setup/templates/steps/config.html @@ -47,11 +47,10 @@ Or in plain english: if receivers start to classify your mail as spam, this post
- +

/minute; - /hour

+ value="10" required > / minute +

diff --git a/towncrier/newsfragments/1098.misc b/towncrier/newsfragments/1098.misc new file mode 100644 index 00000000..d99aa24d --- /dev/null +++ b/towncrier/newsfragments/1098.misc @@ -0,0 +1 @@ +Ignore newlines and comment-lines in postfix overrides - this means you can now make your override configfiles much more readable. diff --git a/towncrier/newsfragments/1268.feature b/towncrier/newsfragments/1268.feature new file mode 100644 index 00000000..e4cf9a5a --- /dev/null +++ b/towncrier/newsfragments/1268.feature @@ -0,0 +1 @@ +The roundcube container does support mysql now (no setup integration yet) diff --git a/towncrier/newsfragments/1320.feature b/towncrier/newsfragments/1320.feature new file mode 100644 index 00000000..fc3fd5aa --- /dev/null +++ b/towncrier/newsfragments/1320.feature @@ -0,0 +1 @@ +Allow users to use server-sided full-text-search again by adding the dovecot fts-xapian plugin diff --git a/towncrier/newsfragments/1357.feature b/towncrier/newsfragments/1357.feature new file mode 100644 index 00000000..56fa443f --- /dev/null +++ b/towncrier/newsfragments/1357.feature @@ -0,0 +1 @@ +Relay a domain to a nonstandard SMTP port by adding ":" to the remote hostname or IP address. \ No newline at end of file diff --git a/towncrier/newsfragments/328.feature b/towncrier/newsfragments/328.feature new file mode 100644 index 00000000..b73b478e --- /dev/null +++ b/towncrier/newsfragments/328.feature @@ -0,0 +1 @@ +Add support for backward-forwarding using SRS \ No newline at end of file diff --git a/webmails/roundcube/Dockerfile b/webmails/roundcube/Dockerfile index c0458015..d4e34c10 100644 --- a/webmails/roundcube/Dockerfile +++ b/webmails/roundcube/Dockerfile @@ -16,13 +16,13 @@ RUN apt-get update && apt-get install -y \ # Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube RUN pip3 install socrate -ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.4.2/roundcubemail-1.4.2-complete.tar.gz +ENV ROUNDCUBE_URL https://github.com/roundcube/roundcubemail/releases/download/1.4.3/roundcubemail-1.4.3-complete.tar.gz RUN apt-get update && apt-get install -y \ - zlib1g-dev libzip4 libzip-dev \ + zlib1g-dev libzip4 libzip-dev libpq-dev \ python3-jinja2 \ gpg \ - && docker-php-ext-install zip \ + && docker-php-ext-install zip pdo_mysql pdo_pgsql \ && echo date.timezone=UTC > /usr/local/etc/php/conf.d/timezone.ini \ && rm -rf /var/www/html/ \ && cd /var/www \ diff --git a/webmails/roundcube/config.inc.php b/webmails/roundcube/config.inc.php index d3f38bc4..2a58e8d5 100644 --- a/webmails/roundcube/config.inc.php +++ b/webmails/roundcube/config.inc.php @@ -3,7 +3,7 @@ $config = array(); // Generals -$config['db_dsnw'] = 'sqlite:////data/roundcube.db'; +$config['db_dsnw'] = getenv('DB_DSNW');; $config['temp_dir'] = '/tmp/'; $config['des_key'] = getenv('SECRET_KEY'); $config['cipher_method'] = 'AES-256-CBC'; diff --git a/webmails/roundcube/start.py b/webmails/roundcube/start.py index 55832dd0..ef913a2b 100755 --- a/webmails/roundcube/start.py +++ b/webmails/roundcube/start.py @@ -4,16 +4,61 @@ import os import logging as log import sys from socrate import conf +import subprocess log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING")) os.environ["MAX_FILESIZE"] = str(int(int(os.environ.get("MESSAGE_SIZE_LIMIT"))*0.66/1048576)) +db_flavor=os.environ.get("ROUNDCUBE_DB_FLAVOR",os.environ.get("DB_FLAVOR","sqlite")) +if db_flavor=="sqlite": + os.environ["DB_DSNW"]="sqlite:////data/roundcube.db" +elif db_flavor=="mysql": + os.environ["DB_DSNW"]="mysql://%s:%s@%s/%s" % ( + os.environ.get("ROUNDCUBE_DB_USER","roundcube"), + os.environ.get("ROUNDCUBE_DB_PW"), + os.environ.get("ROUNDCUBE_DB_HOST",os.environ.get("DB_HOST","database")), + os.environ.get("ROUNDCUBE_DB_NAME","roundcube") + ) +elif db_flavor=="postgresql": + os.environ["DB_DSNW"]="pgsql://%s:%s@%s/%s" % ( + os.environ.get("ROUNDCUBE_DB_USER","roundcube"), + os.environ.get("ROUNDCUBE_DB_PW"), + os.environ.get("ROUNDCUBE_DB_HOST",os.environ.get("DB_HOST","database")), + os.environ.get("ROUNDCUBE_DB_NAME","roundcube") + ) +else: + print("Unknown ROUNDCUBE_DB_FLAVOR: %s",db_flavor) + exit(1) + + + conf.jinja("/php.ini", os.environ, "/usr/local/etc/php/conf.d/roundcube.ini") # Fix some permissions -os.system("mkdir -p /data/gpg") -os.system("chown -R www-data:www-data /data") +os.system("mkdir -p /data/gpg /var/www/html/logs") +os.system("touch /var/www/html/logs/errors") +os.system("chown -R www-data:www-data /data /var/www/html/logs") + +try: + print("Initializing database") + result=subprocess.check_output(["/var/www/html/bin/initdb.sh","--dir","/var/www/html/SQL"],stderr=subprocess.STDOUT) + print(result.decode()) +except subprocess.CalledProcessError as e: + if "already exists" in e.stdout.decode(): + print("Already initialzed") + else: + print(e.stdout.decode()) + quit(1) + +try: + print("Upgrading database") + subprocess.check_call(["/var/www/html/bin/update.sh","--version=?","-y"],stderr=subprocess.STDOUT) +except subprocess.CalledProcessError as e: + quit(1) + +# Tail roundcube logs +subprocess.Popen(["tail","-f","-n","0","/var/www/html/logs/errors"]) # Run apache os.execv("/usr/local/bin/apache2-foreground", ["apache2-foreground"])