Commit 9d23d95c authored by J08nY's avatar J08nY

Add list key management, for owners.

parent 4207a3f3
Pipeline #10987415 failed with stage
in 1 minute and 33 seconds
......@@ -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.')
)
......@@ -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')
{% 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 %}
......@@ -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 = [
......
......@@ -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')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment