aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/django_pgpmailman/forms.py33
-rw-r--r--src/django_pgpmailman/models.py15
-rw-r--r--src/django_pgpmailman/templates/django_pgpmailman/list/key_management.html14
-rw-r--r--src/django_pgpmailman/urls.py11
-rw-r--r--src/django_pgpmailman/views/list.py59
5 files changed, 98 insertions, 34 deletions
diff --git a/src/django_pgpmailman/forms.py b/src/django_pgpmailman/forms.py
index 07761df..493d3d8 100644
--- a/src/django_pgpmailman/forms.py
+++ b/src/django_pgpmailman/forms.py
@@ -16,8 +16,11 @@
# 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 django import forms
+from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
+from pgpy import PGPKey
+from pgpy.errors import PGPError
class NullBooleanRadioSelect(forms.RadioSelect):
@@ -163,3 +166,33 @@ class ListMiscSettingsForm(forms.Form):
help_text=_('A set of member roles that are allowed to sign the '
'lists public key via the `key sign` command.')
)
+
+
+class KeyFileField(forms.FileField):
+ def to_python(self, data):
+ try:
+ return PGPKey.from_blob(data.read())[0]
+ except PGPError as e:
+ raise ValidationError(str(e), code='invalid')
+
+
+class ListKeyManagementForm(forms.Form):
+ key = KeyFileField(
+ widget=forms.ClearableFileInput(),
+ required=False,
+ label=_('Upload a new private key'),
+ help_text=_('Useful for uploading a complately different list key '
+ 'than the one generated by mailman-pgp, when setting '
+ 'up a new mailing list. The uploaded key must be a '
+ 'private PGP key, not expired and must be usable for '
+ 'encryption and signatures.')
+ )
+ pubkey = KeyFileField(
+ widget=forms.ClearableFileInput(),
+ required=False,
+ label=_('Upload a public key'),
+ help_text=_('New signatures from the uploaded key are merged with '
+ 'the current list key, provided the uploaded key '
+ 'has the same key material and contains the UID that '
+ 'was signed.')
+ )
diff --git a/src/django_pgpmailman/models.py b/src/django_pgpmailman/models.py
index 406ae76..0a49475 100644
--- a/src/django_pgpmailman/models.py
+++ b/src/django_pgpmailman/models.py
@@ -23,7 +23,6 @@ from itertools import chain
from mailmanclient._client import MailingList, RESTObject
from pgpy import PGPKey
from pgpy.errors import PGPError
-from six.moves.urllib_error import HTTPError
class PGPMailingList(RESTObject):
@@ -51,11 +50,8 @@ class PGPMailingList(RESTObject):
@key.setter
def key(self, value):
str_key = str(value) if value else ''
- try:
- self._connection.call(self._url + '/key', data=dict(key=str_key),
- method='PUT')
- except HTTPError:
- pass
+ self._connection.call(self._url + '/key', data=dict(key=str_key),
+ method='PUT')
@property
def pubkey(self):
@@ -65,3 +61,10 @@ class PGPMailingList(RESTObject):
return key
except PGPError:
return None
+
+ @pubkey.setter
+ def pubkey(self, value):
+ str_key = str(value) if value else ''
+ self._connection.call(self._url + '/pubkey',
+ data=dict(public_key=str_key),
+ method='PUT')
diff --git a/src/django_pgpmailman/templates/django_pgpmailman/list/key_management.html b/src/django_pgpmailman/templates/django_pgpmailman/list/key_management.html
index 739c604..9811733 100644
--- a/src/django_pgpmailman/templates/django_pgpmailman/list/key_management.html
+++ b/src/django_pgpmailman/templates/django_pgpmailman/list/key_management.html
@@ -1,13 +1,19 @@
{% extends "django_pgpmailman/base.html" %}
{% load i18n %}
-
+{% load bootstrap_tags %}
{% block head_title %}
{% trans 'PGP List' %} - {{ block.super }}
{% endblock %}
{% block content %}
- {% with mlist=pgp_list.mlist %}
- {% include 'django_pgpmailman/list/nav.html' with nav_tab='key_management' nav_title='List key management' %}
+ {% include 'django_pgpmailman/list/nav.html' with nav_tab='key_management' nav_title='List key management' %}
- {% endwith %}
+ <p>Fingerprint: {{ pgp_list.key.fingerprint }}</p>
+ Download the list <a href="{% url 'pgp_list_privkey' pgp_list.list_id %}">private key</a>.
+ <form action="{% url 'pgp_list_key_management' pgp_list.list_id %}"
+ method="post"
+ class="form-horizontal"
+ enctype="multipart/form-data">
+ {% bootstrap_form_horizontal form 3 8 'Save changes' %}
+ </form>
{% endblock content %}
diff --git a/src/django_pgpmailman/urls.py b/src/django_pgpmailman/urls.py
index abfff27..6276b82 100644
--- a/src/django_pgpmailman/urls.py
+++ b/src/django_pgpmailman/urls.py
@@ -20,14 +20,16 @@ from __future__ import absolute_import, unicode_literals
from django.conf.urls import url, include
from django_pgpmailman.views.list import (
- pgp_list_index, pgp_list_summary, pgp_list_pubkey, pgp_list_key_management,
+ pgp_list_index, pgp_list_summary,
ListSignatureSettingsView, ListEncryptionSettingsView,
- ListMiscSettingsView)
+ ListMiscSettingsView, ListKeyManagementView, ListPubkey, ListPrivkey)
from django_pgpmailman.views.user import pgp_user_profile
list_patterns = [
url(r'^$', pgp_list_summary, name='pgp_list_summary'),
- url(r'^key/$', pgp_list_key_management, name='pgp_list_key_management'),
+ url(r'^key/$',
+ ListKeyManagementView.as_view(success_url='pgp_list_key_management'),
+ name='pgp_list_key_management'),
url(r'^signatures/$', ListSignatureSettingsView.as_view(
success_url='pgp_list_signature_settings'),
name='pgp_list_signature_settings'),
@@ -37,7 +39,8 @@ list_patterns = [
url(r'^misc/$',
ListMiscSettingsView.as_view(success_url='pgp_list_misc_settings'),
name='pgp_list_misc_settings'),
- url(r'^pubkey$', pgp_list_pubkey, name='pgp_list_pubkey')
+ url(r'^pubkey$', ListPubkey.as_view(), name='pgp_list_pubkey'),
+ url(r'^privkey$', ListPrivkey.as_view(), name='pgp_list_privkey')
]
user_patterns = [
diff --git a/src/django_pgpmailman/views/list.py b/src/django_pgpmailman/views/list.py
index d887d7a..5e64b85 100644
--- a/src/django_pgpmailman/views/list.py
+++ b/src/django_pgpmailman/views/list.py
@@ -21,11 +21,12 @@ from __future__ import absolute_import, unicode_literals
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.files.base import ContentFile
-from django.http import HttpResponse
+from django.http import HttpResponse, Http404
from django.shortcuts import render
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _
+from django.views import View
from django.views.generic import FormView
from six.moves.urllib.error import HTTPError
@@ -33,7 +34,8 @@ from django_pgpmailman.decorators import (list_view, list_class_view,
member_role_required)
from django_pgpmailman.forms import (ListSignatureSettingsForm,
ListEncryptionSettingsForm,
- ListMiscSettingsForm)
+ ListMiscSettingsForm,
+ ListKeyManagementForm)
from django_pgpmailman.plugin import get_pgp_plugin
@@ -48,18 +50,39 @@ def pgp_list_summary(request, pgp_list):
{'pgp_list': pgp_list})
-@list_view
-def pgp_list_pubkey(request, pgp_list):
- pubkey = pgp_list.pubkey
- pubkey_file = ContentFile(str(pubkey))
- response = HttpResponse(pubkey_file, 'application/pgp-keys')
- response['Content-Length'] = pubkey_file.size
- response[
- 'Content-Disposition'] = 'attachment; filename="%s.asc"' % pgp_list.list_id
- return response
+class ListKey(View):
+ which_key = None
+
+ def get(self, request):
+ key = getattr(self.pgp_list, self.which_key)
+ if key is None:
+ raise Http404
+ key_file = ContentFile(str(key))
+ response = HttpResponse(key_file, 'application/pgp-keys')
+ response['Content-Length'] = key_file.size
+ response[
+ 'Content-Disposition'] = 'attachment; filename="%s.asc"' % self.pgp_list.list_id
+ return response
+
+
+class ListPubkey(ListKey):
+ which_key = 'pubkey'
+
+ @list_class_view
+ def dispatch(self, request, *args, **kwargs):
+ return super(ListKey, self).dispatch(request, *args, **kwargs)
+
+
+class ListPrivkey(ListKey):
+ which_key = 'key'
+
+ @method_decorator(login_required)
+ @list_class_view
+ @member_role_required('owner')
+ def dispatch(self, request, *args, **kwargs):
+ return super(ListPrivkey, self).dispatch(request, *args, **kwargs)
-@method_decorator(login_required, name='dispatch')
class ListSettings(FormView):
properties = None
@@ -76,6 +99,7 @@ class ListSettings(FormView):
data['mlist'] = self.pgp_list.mlist
return data
+ @method_decorator(login_required)
@list_class_view
@member_role_required('owner')
def dispatch(self, request, *args, **kwargs):
@@ -130,11 +154,6 @@ class ListMiscSettingsView(ListSettings):
class ListKeyManagementView(ListSettings):
- pass
-
-
-@login_required
-@list_view
-def pgp_list_key_management(request, pgp_list):
- return render(request, 'django_pgpmailman/list/key_management.html',
- {'pgp_list': pgp_list})
+ form_class = ListKeyManagementForm
+ template_name = 'django_pgpmailman/list/key_management.html'
+ properties = ('key', 'pubkey')