aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJ08nY2017-06-18 02:08:19 +0200
committerJ08nY2017-06-18 02:08:19 +0200
commitb8767a634966b2c4ea9b2c8a71174ca49e3c2f2f (patch)
treeab55c0fc3f44342e7161245c015061ca306b593c /src
parentaa407033bdb43cf09b1eeff2aa06a80a78ee00d7 (diff)
downloadmailman-pgp-b8767a634966b2c4ea9b2c8a71174ca49e3c2f2f.tar.gz
mailman-pgp-b8767a634966b2c4ea9b2c8a71174ca49e3c2f2f.tar.zst
mailman-pgp-b8767a634966b2c4ea9b2c8a71174ca49e3c2f2f.zip
Diffstat (limited to 'src')
-rw-r--r--src/mailman_pgp/config/mailman_pgp.cfg17
-rw-r--r--src/mailman_pgp/model/list.py33
-rw-r--r--src/mailman_pgp/pgp/__init__.py22
-rw-r--r--src/mailman_pgp/pgp/keygen.py29
-rw-r--r--src/mailman_pgp/plugin.py2
5 files changed, 89 insertions, 14 deletions
diff --git a/src/mailman_pgp/config/mailman_pgp.cfg b/src/mailman_pgp/config/mailman_pgp.cfg
index 0abb026..de87ca1 100644
--- a/src/mailman_pgp/config/mailman_pgp.cfg
+++ b/src/mailman_pgp/config/mailman_pgp.cfg
@@ -6,7 +6,7 @@ url = sqlite:////$DATA_DIR/pgp.db
[gpg]
-# GPG homedir
+# GPG homedir.
homedir = $DATA_DIR/gpg/
# Keyring used to store user keys. (GPG pubring)
@@ -15,11 +15,22 @@ keyring = $DATA_DIR/gpg/pubring.gpg
# Keyring used to store list keypairs. (GPG secring)
secring = $DATA_DIR/gpg/secring.gpg
+# The GPG binary to use.
+binary = gpg
+
[keypairs]
-size = 4096
+#
+key_length = 4096
+
+#
+key_type = RSA
+
+#
+subkey_length = 4096
-type = RSA
+#
+subkey_type = RSA
[queues]
diff --git a/src/mailman_pgp/model/list.py b/src/mailman_pgp/model/list.py
index d6384af..4699599 100644
--- a/src/mailman_pgp/model/list.py
+++ b/src/mailman_pgp/model/list.py
@@ -1,11 +1,14 @@
""""""
+from mailman.config import config as mailman_config
from mailman.database.types import Enum, SAUnicode
from mailman.interfaces.action import Action
+from mailman.model.mailinglist import MailingList
from public import public
from sqlalchemy import Boolean, Column, Integer
from mailman_pgp.model.base import Base
+from mailman_pgp.pgp.keygen import KeyGenerator
@public
@@ -14,7 +17,7 @@ class EncryptedMailingList(Base):
id = Column(Integer, primary_key=True)
list_id = Column(SAUnicode, index=True)
- key_fingerprint = Column(SAUnicode)
+ _key_fingerprint = Column('key_fingerprint', SAUnicode)
unsigned_msg_action = Column(Enum(Action))
nonencrypted_msg_action = Column(Enum(Action))
strip_original_signature = Column(Boolean)
@@ -23,10 +26,28 @@ class EncryptedMailingList(Base):
def __init__(self, mlist):
super().__init__()
self.list_id = mlist.list_id
- self._list_key = None
+
+ self._key_generator = self._create_generator(mlist)
+ self._key_generator.start()
+
+ def _create_generator(self, mlist):
+ return KeyGenerator(mlist.list_id, mlist.fqdn_listname)
+
+ @property
+ def key_fingerprint(self):
+ if self._key_fingerprint is None:
+ if self._key_generator.has_key:
+ self._key_fingerprint = self._key_generator.key_fingerprint
+ else:
+ if not self._key_generator.is_alive():
+ # TODO this is not the best solution, we should lookup the
+ # key by mlist.fqdn_listname, if it actually got created
+ # and key generator didn't receive it.
+ self._key_generator = self._create_generator(self.mlist)
+ self._key_generator.start()
+ return self._key_fingerprint
@property
- def list_key(self):
- if self._list_key is not None:
- return self._list_key
- pass
+ def mlist(self):
+ return mailman_config.db.query(MailingList).filter_by(
+ _list_id=self.list_id).first()
diff --git a/src/mailman_pgp/pgp/__init__.py b/src/mailman_pgp/pgp/__init__.py
index c96d1b0..ec31b2d 100644
--- a/src/mailman_pgp/pgp/__init__.py
+++ b/src/mailman_pgp/pgp/__init__.py
@@ -1,5 +1,7 @@
""""""
+from pathlib import Path
+
import gpgmime
from mailman.config import config as mailman_config
from mailman.utilities.string import expand
@@ -8,15 +10,27 @@ from public import public
from mailman_pgp.config import config
GPG_CONFIG_PATHS = ['homedir', 'keyring', 'secring', 'binary']
+KEYPAIR_CONFIG_VARIABLES = ['key_type', 'key_length',
+ 'subkey_type', 'subkey_length']
@public
class GPG(gpgmime.GPG):
def __init__(self):
- self.list_key_size = config.getint('keypairs', 'size')
- self.list_key_type = config.get('keypairs', 'type')
+ # Get all the [keypairs] config variables.
+ self.keypair_config = dict(
+ (k, config.get('keypairs', k)) for k in KEYPAIR_CONFIG_VARIABLES)
+ self.keypair_config['key_usage'] = 'auth,sign,cert'
+ self.keypair_config['subkey_usage'] = 'enc'
- gpg_config = dict(
+ # Get and expand all [gpg] config paths against Mailman's directories.
+ self.gpg_config = dict(
(k, expand(config.get('gpg', k), None, mailman_config.paths))
for k in GPG_CONFIG_PATHS)
- super().__init__(**gpg_config)
+
+ # Ensure that the homedir path is a directory before passing it to GPG.
+ # If it's actually a file this raises FileExistsError.
+ homedir_path = Path(self.gpg_config['homedir'])
+ homedir_path.mkdir(parents=True, exist_ok=True)
+
+ super().__init__(**self.gpg_config)
diff --git a/src/mailman_pgp/pgp/keygen.py b/src/mailman_pgp/pgp/keygen.py
new file mode 100644
index 0000000..b15dbf6
--- /dev/null
+++ b/src/mailman_pgp/pgp/keygen.py
@@ -0,0 +1,29 @@
+""""""
+
+import threading
+
+from mailman_pgp.config import config
+
+
+class KeyGenerator(threading.Thread):
+ def __init__(self, name, email, comment=None):
+ super().__init__(daemon=True)
+ self._name = name
+ self._comment = comment
+ self._email = email
+ self.key_fingerprint = None
+
+ def run(self):
+ default_config = config.gpg.keypair_config
+ key_config = dict(default_config)
+ key_config.update(dict(name_real=self._name,
+ name_email=self._email))
+ if self._comment is not None:
+ key_config['name_comment'] = self._comment
+ key_input = config.gpg.gen_key_input(**key_config)
+ key = config.gpg.gen_key(key_input)
+ self.key_fingerprint = key.fingerprint
+
+ @property
+ def has_key(self):
+ return self.key_fingerprint is not None
diff --git a/src/mailman_pgp/plugin.py b/src/mailman_pgp/plugin.py
index 6921095..5245a95 100644
--- a/src/mailman_pgp/plugin.py
+++ b/src/mailman_pgp/plugin.py
@@ -37,4 +37,4 @@ def on_delete(mlist):
if encrypted_list:
with transaction():
config.db.session.delete(encrypted_list)
- # delete the keypairs here
+ # TODO delete the keypairs here