aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman_pgp/commands/eml_key.py5
-rw-r--r--src/mailman_pgp/commands/tests/test_key.py24
-rw-r--r--src/mailman_pgp/model/list.py4
-rw-r--r--src/mailman_pgp/workflows/base.py2
-rw-r--r--src/mailman_pgp/workflows/key_change.py42
-rw-r--r--src/mailman_pgp/workflows/mod_approval.py62
-rw-r--r--src/mailman_pgp/workflows/pubkey.py3
-rw-r--r--src/mailman_pgp/workflows/tests/test_mod_approval.py16
8 files changed, 136 insertions, 22 deletions
diff --git a/src/mailman_pgp/commands/eml_key.py b/src/mailman_pgp/commands/eml_key.py
index bea9745..d493108 100644
--- a/src/mailman_pgp/commands/eml_key.py
+++ b/src/mailman_pgp/commands/eml_key.py
@@ -28,6 +28,7 @@ from public import public
from zope.component import getUtility
from zope.interface import implementer
+from mailman_pgp.config import mm_config
from mailman_pgp.database import transaction
from mailman_pgp.model.address import PGPAddress
from mailman_pgp.model.list import PGPMailingList
@@ -236,7 +237,9 @@ def _cmd_change(pgp_list, mlist, msg, msgdata, arguments, results):
file=results)
return ContinueProcessing.no
- workflow = KeyChangeWorkflow(mlist, pgp_address, key)
+ workflow_class = mm_config.workflows[pgp_list.key_change_workflow]
+
+ workflow = workflow_class(mlist, pgp_address, key)
list(workflow)
print('Key change request received.', file=results)
return ContinueProcessing.no
diff --git a/src/mailman_pgp/commands/tests/test_key.py b/src/mailman_pgp/commands/tests/test_key.py
index 0c7d7c7..674438d 100644
--- a/src/mailman_pgp/commands/tests/test_key.py
+++ b/src/mailman_pgp/commands/tests/test_key.py
@@ -27,13 +27,13 @@ from mailman.runners.command import CommandRunner
from mailman.testing.helpers import get_queue_messages, make_testable_runner
from mailman.utilities.datetime import now
from pgpy import PGPKey, PGPUID
-from pgpy.constants import (PubKeyAlgorithm, KeyFlags, EllipticCurveOID,
- HashAlgorithm, SymmetricKeyAlgorithm,
- CompressionAlgorithm)
+from pgpy.constants import (
+ CompressionAlgorithm, EllipticCurveOID, HashAlgorithm, KeyFlags,
+ PubKeyAlgorithm, SymmetricKeyAlgorithm)
from zope.component import getUtility
from mailman_pgp.config import mm_config
-from mailman_pgp.database import transaction
+from mailman_pgp.database import transaction, mm_transaction
from mailman_pgp.model.address import PGPAddress
from mailman_pgp.model.list import PGPMailingList
from mailman_pgp.pgp.mime import MIMEWrapper
@@ -128,8 +128,7 @@ class TestPreSubscription(unittest.TestCase):
hashes=[HashAlgorithm.SHA256,
HashAlgorithm.SHA512],
ciphers=[SymmetricKeyAlgorithm.AES256],
- compression=[CompressionAlgorithm.ZLIB,
- CompressionAlgorithm.Uncompressed]
+ compression=[CompressionAlgorithm.ZLIB]
)
def test_set(self):
@@ -594,9 +593,13 @@ class TestAfterSubscription(unittest.TestCase):
layer = PGPConfigLayer
def setUp(self):
- self.mlist = create_list('test@example.com', style_name='pgp-default')
- self.pgp_list = PGPMailingList.for_list(self.mlist)
- self.pgp_list.key = load_key('ecc_p256.priv.asc')
+ with mm_transaction():
+ self.mlist = create_list('test@example.com',
+ style_name='pgp-default')
+ with transaction():
+ self.pgp_list = PGPMailingList.for_list(self.mlist)
+ self.pgp_list.key = load_key('ecc_p256.priv.asc')
+ self.pgp_list.key_change_workflow = 'pgp-key-change-workflow'
self.bart_key = load_key('rsa_1024.priv.asc')
self.bart_new_key = load_key('ecc_p256.priv.asc')
@@ -611,8 +614,7 @@ class TestAfterSubscription(unittest.TestCase):
hashes=[HashAlgorithm.SHA256,
HashAlgorithm.SHA512],
ciphers=[SymmetricKeyAlgorithm.AES256],
- compression=[CompressionAlgorithm.ZLIB,
- CompressionAlgorithm.Uncompressed]
+ compression=[CompressionAlgorithm.ZLIB]
)
def test_change(self):
diff --git a/src/mailman_pgp/model/list.py b/src/mailman_pgp/model/list.py
index d80f4a7..9c2d317 100644
--- a/src/mailman_pgp/model/list.py
+++ b/src/mailman_pgp/model/list.py
@@ -54,6 +54,10 @@ class PGPMailingList(Base):
nonencrypted_msg_action = Column(Enum(Action), default=Action.reject)
encrypt_outgoing = Column(Boolean, default=True)
+ # Key related properties
+ key_change_workflow = Column(SAUnicode,
+ default='pgp-key-change-mod-workflow')
+
def __init__(self, mlist):
"""
diff --git a/src/mailman_pgp/workflows/base.py b/src/mailman_pgp/workflows/base.py
index 036dc18..42515e2 100644
--- a/src/mailman_pgp/workflows/base.py
+++ b/src/mailman_pgp/workflows/base.py
@@ -16,11 +16,13 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
""""""
+from public import public
from mailman_pgp.database import transaction
from mailman_pgp.model.address import PGPAddress
+@public
class PGPMixin:
def _step_pgp_prepare(self):
pgp_address = PGPAddress.for_address(self.address)
diff --git a/src/mailman_pgp/workflows/key_change.py b/src/mailman_pgp/workflows/key_change.py
index 290e504..2ef82a8 100644
--- a/src/mailman_pgp/workflows/key_change.py
+++ b/src/mailman_pgp/workflows/key_change.py
@@ -32,6 +32,7 @@ from mailman_pgp.model.address import PGPAddress
from mailman_pgp.model.list import PGPMailingList
from mailman_pgp.pgp.wrapper import PGPWrapper
from mailman_pgp.utils.email import copy_headers
+from mailman_pgp.workflows.mod_approval import ModeratorApprovalMixin
CHANGE_CONFIRM_REQUEST = """\
----------
@@ -46,12 +47,7 @@ Token: {}
"""
-@public
-@implementer(IWorkflow)
-class KeyChangeWorkflow(Workflow):
- name = 'pgp-key-change-workflow'
- description = ''
- initial_state = 'change_key'
+class KeyChangeBase(Workflow):
save_attributes = (
'address_key',
'pubkey_key'
@@ -116,16 +112,17 @@ class KeyChangeWorkflow(Workflow):
raise StopIteration
def _step_receive_confirmation(self):
- with transaction():
- self.pgp_address.key = self.pubkey
- self.pgp_address.key_confirmed = True
-
pendings = getUtility(IPendings)
if self.token is not None:
pendings.confirm(self.token)
self.token = None
self.token_owner = TokenOwner.no_one
+ def _step_do_change(self):
+ with transaction():
+ self.pgp_address.key = self.pubkey
+ self.pgp_address.key_confirmed = True
+
@classmethod
def pendable_class(cls):
@implementer(IPendable)
@@ -133,3 +130,28 @@ class KeyChangeWorkflow(Workflow):
PEND_TYPE = KeyChangeWorkflow.name
return Pendable
+
+
+@public
+@implementer(IWorkflow)
+class KeyChangeWorkflow(KeyChangeBase):
+ name = 'pgp-key-change-workflow'
+ description = ''
+ initial_state = 'prepare'
+
+ def _step_prepare(self):
+ self.push('do_change')
+ self.push('change_key')
+
+
+@public
+@implementer(IWorkflow)
+class KeyChangeModWorkflow(KeyChangeBase, ModeratorApprovalMixin):
+ name = 'pgp-key-change-mod-workflow'
+ description = ''
+ initial_state = 'prepare'
+
+ def _step_prepare(self):
+ self.push('do_change')
+ self.push('mod_approval')
+ self.push('change_key')
diff --git a/src/mailman_pgp/workflows/mod_approval.py b/src/mailman_pgp/workflows/mod_approval.py
new file mode 100644
index 0000000..e7ff061
--- /dev/null
+++ b/src/mailman_pgp/workflows/mod_approval.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2017 Jan Jancar
+#
+# This file is a part of the Mailman PGP plugin.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+
+""""""
+
+from mailman.email.message import UserNotification
+from mailman.interfaces.subscriptions import TokenOwner
+from public import public
+
+from mailman_pgp.pgp.mime import MIMEWrapper
+
+MOD_APPROVAL_REQUEST = """\
+----------
+TODO: this is a pgp enabled list.
+A subscriber with address {} requested a change of his key.
+His new key is attached to this message.
+
+Fingerprint: {}
+----------
+"""
+
+
+@public
+class ModeratorApprovalMixin:
+ def _step_mod_approval(self):
+ self.push('restore')
+ self.push('get_approval')
+
+ def _step_get_approval(self):
+ self._set_token(TokenOwner.moderator)
+ self.push('restore')
+ self.save()
+
+ if self.mlist.admin_immed_notify:
+ subject = 'New key change request to {} from {}'.format(
+ self.mlist.display_name, self.pgp_address.email)
+ text = MOD_APPROVAL_REQUEST.format(self.pgp_address.email,
+ self.pubkey.fingerprint)
+ msg = UserNotification(
+ self.mlist.owner_address, self.mlist.owner_address,
+ subject, text, self.mlist.preferred_language)
+ wrapped = MIMEWrapper(msg)
+ msg = wrapped.attach_keys(self.pubkey)
+ msg.send(self.mlist)
+ raise StopIteration
+
+ def _step_restore(self):
+ self._set_token(TokenOwner.no_one)
diff --git a/src/mailman_pgp/workflows/pubkey.py b/src/mailman_pgp/workflows/pubkey.py
index a13d491..65ea74d 100644
--- a/src/mailman_pgp/workflows/pubkey.py
+++ b/src/mailman_pgp/workflows/pubkey.py
@@ -1,6 +1,7 @@
from mailman.email.message import UserNotification
from mailman.interfaces.subscriptions import TokenOwner
from pgpy import PGPKey
+from public import public
from mailman_pgp.database import transaction
from mailman_pgp.model.address import PGPAddress
@@ -27,6 +28,7 @@ Token: {}
"""
+@public
class SetPubkeyMixin:
def __init__(self, pubkey=None):
self.pubkey = pubkey
@@ -73,6 +75,7 @@ class SetPubkeyMixin:
self._set_token(TokenOwner.no_one)
+@public
class ConfirmPubkeyMixin:
def __init__(self, pre_confirmed=False):
self.pubkey_confirmed = pre_confirmed
diff --git a/src/mailman_pgp/workflows/tests/test_mod_approval.py b/src/mailman_pgp/workflows/tests/test_mod_approval.py
new file mode 100644
index 0000000..8b6b4d1
--- /dev/null
+++ b/src/mailman_pgp/workflows/tests/test_mod_approval.py
@@ -0,0 +1,16 @@
+# Copyright (C) 2017 Jan Jancar
+#
+# This file is a part of the Mailman PGP plugin.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.