1
0
mirror of https://github.com/Mailu/Mailu.git synced 2025-10-30 23:37:43 +02:00

Handle DKIM key generation and storage

This commit is contained in:
Pierre Jaury
2016-06-25 15:50:05 +02:00
parent 2fa8b879db
commit 24680957f7
7 changed files with 75 additions and 5 deletions

View File

@@ -20,7 +20,9 @@ default_config = {
'HOSTNAME': 'mail.freeposte.io',
'DOMAIN': 'freeposte.io',
'POSTMASTER': 'postmaster',
'DEBUG': False
'DEBUG': False,
'DKIM_PATH': '/dkim/{domain}.{selector}.key',
'DKIM_SELECTOR': 'dkim'
}
# Load configuration from the environment if available

View File

@@ -0,0 +1,21 @@
""" No crypto operation is done on keys.
They are thus represented as ASCII armored PEM.
"""
from OpenSSL import crypto
def gen_key(key_type=crypto.TYPE_RSA, bits=1024):
""" Generate and return a new RSA key.
"""
key = crypto.PKey()
key.generate_key(key_type, bits)
return crypto.dump_privatekey(crypto.FILETYPE_PEM, key)
def strip_key(pem):
""" Return only the b64 part of the ASCII armored PEM.
"""
key = crypto.load_privatekey(crypto.FILETYPE_PEM, pem)
public_pem = crypto.dump_publickey(crypto.FILETYPE_PEM, key)
return public_pem.replace(b"\n", b"").split(b"-----")[2]

View File

@@ -1,10 +1,14 @@
from freeposte.admin import db
from freeposte.admin import db, dkim
from freeposte import app
from sqlalchemy.ext import declarative
from passlib import context
from datetime import datetime
import re
import time
import os
import glob
# Many-to-many association table for domain managers
@@ -34,6 +38,28 @@ class Domain(Base):
max_users = db.Column(db.Integer, nullable=False, default=0)
max_aliases = db.Column(db.Integer, nullable=False, default=0)
@property
def dkim_key(self):
file_path = app.config["DKIM_PATH"].format(
domain=self.name, selector=app.config["DKIM_SELECTOR"])
if os.path.exists(file_path):
with open(file_path, "rb") as handle:
return handle.read()
@dkim_key.setter
def dkim_key(self, value):
file_path = app.config["DKIM_PATH"].format(
domain=self.name, selector=app.config["DKIM_SELECTOR"])
with open(file_path, "wb") as handle:
handle.write(value)
@property
def dkim_publickey(self):
return dkim.strip_key(self.dkim_key).decode("utf8")
def generate_dkim_key(self):
self.dkim_key = dkim.gen_key()
def has_email(self, localpart):
for email in self.users + self.aliases:
if email.localpart == localpart:

View File

@@ -10,7 +10,7 @@ Domain details
{% block main_action %}
{% if current_user.global_admin %}
<a class="btn btn-primary" href="#">Regenerate keys</a>
<a class="btn btn-primary" href="{{ url_for(".domain_genkeys", domain_name=domain.name) }}">Regenerate keys</a>
{% endif %}
{% endblock %}
@@ -26,8 +26,18 @@ Domain details
<td><pre>{{ domain.name }}. 600 IN MX 10 {{ config["HOSTNAME"] }}.</pre></td>
</tr>
<tr>
<th>DNS SPF entry</th>
<td><pre>{{ domain.name }}. 600 IN TXT "v=spf1 mx a:{{ config["HOSTNAME"] }} -all"</pre></td>
<th>DNS SPF entries</th>
<td><pre>
{{ domain.name }}. 600 IN TXT "v=spf1 mx a:{{ config["HOSTNAME"] }} -all"
{{ domain.name }}. 600 IN SPF "v=spf1 mx a:{{ config["HOSTNAME"] }} -all"</pre></td>
</tr>
<tr>
<th>DKIM public key</th>
<td><pre style="white-space: pre-wrap; word-wrap: break-word;">{{ domain.dkim_publickey }}</pre></td>
</tr>
<tr>
<th>DNS DKIM entry</th>
<td><pre style="white-space: pre-wrap; word-wrap: break-word;">{{ config["DKIM_SELECTOR"] }}._domainkey IN 600 TXT "v=DKIM1; k=rsa; p={{ domain.dkim_publickey }}"</pre></td>
</tr>
<tr>
<th>DNS DMARC entry</th>

View File

@@ -63,3 +63,11 @@ def domain_details(domain_name):
domain = utils.get_domain_admin(domain_name)
return flask.render_template('domain/details.html', domain=domain,
config=flask_app.config)
@app.route('/domain/genkeys/<domain_name>', methods=['GET'])
def domain_genkeys(domain_name):
domain = utils.get_domain_admin(domain_name)
domain.generate_dkim_key()
return flask.redirect(
flask.url_for(".domain_details", domain_name=domain_name))

View File

@@ -6,6 +6,7 @@ Flask-migrate
Flask-script
flask_wtf
WTForms-Components
PyOpenSSL
passlib
gunicorn
docker-py

View File

@@ -55,6 +55,7 @@ services:
env_file: freeposte.env
volumes:
- /freeposte/filter:/data
- /freeposte/dkim:/dkim
antispam:
build: rspamd
@@ -79,6 +80,7 @@ services:
env_file: freeposte.env
volumes:
- /freeposte/freeposte:/data
- /freeposte/dkim:/dkim
- /var/run/docker.sock:/var/run/docker.sock:ro
webmail: