diff --git a/actions/monkeysphere b/actions/monkeysphere index bce21c8fd..6a8b0fc75 100755 --- a/actions/monkeysphere +++ b/actions/monkeysphere @@ -21,42 +21,39 @@ Configuration helper for monkeysphere. """ import argparse +import json import os import subprocess -HOST_TOOL = 'monkeysphere-host' - def parse_arguments(): """Return parsed command line arguments as dictionary.""" parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - host_show_key = subparsers.add_parser('host-show-key', - help='Show host key fingerprint') - host_show_key.add_argument('keyid', nargs='*', - help='Optional list of KEYIDs') + host_show_keys = subparsers.add_parser( + 'host-show-keys', help='Show host key fingerprints') + host_show_keys.add_argument( + 'key_ids', nargs='*', help='Optional list of KEYIDs') - host_import_ssh_key = subparsers.add_parser('host-import-ssh-key', - help='Import host SSH key') - host_import_ssh_key.add_argument('hostname', - help='Fully-qualified hostname') + host_import_ssh_key = subparsers.add_parser( + 'host-import-ssh-key', help='Import host SSH key') + host_import_ssh_key.add_argument( + 'hostname', help='Fully-qualified hostname') host_publish_key = subparsers.add_parser( - 'host-publish-key', - help='Push host key to keyserver') + 'host-publish-key', help='Push host key to keyserver') host_publish_key.add_argument( - 'keyid', nargs='*', - help='Optional list of KEYIDs') + 'key_ids', nargs='*', help='Optional list of KEYIDs') return parser.parse_args() -def subcommand_host_show_key(arguments): - """Show host key fingerprint.""" - keyid = ' '.join(arguments.keyid) +def subcommand_host_show_keys(arguments): + """Show host key fingerprints.""" try: - output = subprocess.check_output([HOST_TOOL, 'show-key', keyid]) + output = subprocess.check_output( + ['monkeysphere-host', 'show-keys'] + arguments.key_ids) except subprocess.CalledProcessError: # no keys available return @@ -75,32 +72,29 @@ def subcommand_host_show_key(arguments): keys[-1]['pgp_fingerprint'] = line.lstrip('Open PGP fingerprint:') elif line.startswith('ssh fingerprint:'): data = line.lstrip('ssh fingerprint:').split() - keys[-1]['ssh_keysize'] = data[0] + keys[-1]['ssh_key_size'] = data[0] keys[-1]['ssh_fingerprint'] = data[1] - keys[-1]['ssh_keytype'] = data[2].strip('()') + keys[-1]['ssh_key_type'] = data[2].strip('()') elif line == '': keys.append(dict()) - for key in keys: - print(key['pub'], key['date'], key['uid'], key['pgp_fingerprint'], - key['ssh_keysize'], key['ssh_fingerprint'], key['ssh_keytype']) + print(json.dumps({'keys': keys})) def subcommand_host_import_ssh_key(arguments): """Import host SSH key.""" output = subprocess.check_output( - [HOST_TOOL, 'import-key', + ['monkeysphere-host', 'import-key', '/etc/ssh/ssh_host_rsa_key', arguments.hostname]) print(output.decode()) def subcommand_host_publish_key(arguments): """Push host key to keyserver.""" - keyid = ' '.join(arguments.keyid) # setting TMPDIR as workaround for Debian bug #656750 proc = subprocess.Popen( - [HOST_TOOL, 'publish-keys', keyid], - stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, + ['monkeysphere-host', 'publish-keys'] + arguments.key_ids, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=dict( os.environ, TMPDIR='/var/lib/monkeysphere/authentication/tmp/', diff --git a/plinth/modules/monkeysphere/templates/monkeysphere.html b/plinth/modules/monkeysphere/templates/monkeysphere.html index fbab833e0..2e67c5204 100644 --- a/plinth/modules/monkeysphere/templates/monkeysphere.html +++ b/plinth/modules/monkeysphere/templates/monkeysphere.html @@ -32,77 +32,81 @@ {% block content %} -

{% trans "Monkeysphere" %}

+

{% trans "Monkeysphere" %}

-

- {% blocktrans trimmed with box_name=cfg.box_name %} - With Monkeysphere, a PGP key can be generated for each domain - serving SSH on this {{ box_name }}. The PGP public key can then be - uploaded to the PGP keyservers. Users connecting to this {{ box_name }} - through SSH can verify that they are connecting to the correct - host. See the - - Monkeysphere SSH documentation for more details. - {% endblocktrans %} -

- -{% if running %} -

- - {% trans "Publishing key to keyserver..." %} - -

- {% csrf_token %} - - -
+

+ {% blocktrans trimmed %} + With Monkeysphere, a PGP key can be generated for each configured domain + serving SSH. The PGP public key can then be uploaded to the PGP + keyservers. Users connecting to this machine through SSH can verify that + they are connecting to the correct host. For users to trust the key, at + least one person (usually the machine owner) must sign the key using the + regular PGP key signing process. See the + + Monkeysphere SSH documentation for more details. + {% endblocktrans %}

-{% endif %} -
-
- - {% for name_service in status.name_services %} - - - - - - {% endfor %} -
- {{ name_service.type }}
- {{ name_service.name }} -
- {% if name_service.key %} - {{ name_service.key.pgp_fingerprint }} - {% else %} - {% trans "Not Available" %} - {% endif %} - - {% if name_service.available %} - {% if not name_service.key %} -
- {% csrf_token %} + {% if running %} +

+ + {% trans "Publishing key to keyserver..." %} - -

+
+ {% csrf_token %} - {% elif not running %} - - {% csrf_token %} + +
+

+ {% endif %} - - - {% endif %} - {% endif %} -
+
+
+ + + + + + + + + + {% for domain in status.domains %} + + + + + + {% endfor %} + +
{% trans "Domain" %}{% trans "GPG Fingerprint" %}{% trans "Actions" %}
{{ domain.name }} + {% if domain.key %} + {{ domain.key.pgp_fingerprint }} + {% else %} + {% trans "Not Available" %} + {% endif %} + + {% if not domain.key %} +
+ {% csrf_token %} + + +
+ {% elif not running %} +
+ {% csrf_token %} + + +
+ {% endif %} +
+
-
{% endblock %} diff --git a/plinth/modules/monkeysphere/urls.py b/plinth/modules/monkeysphere/urls.py index d45cd3855..5d5e20dea 100644 --- a/plinth/modules/monkeysphere/urls.py +++ b/plinth/modules/monkeysphere/urls.py @@ -26,9 +26,9 @@ from . import views urlpatterns = [ url(r'^sys/monkeysphere/$', views.index, name='index'), - url(r'^sys/monkeysphere/(?P[\w]+)/generate/$', + url(r'^sys/monkeysphere/(?P[^/]+)/generate/$', views.generate, name='generate'), - url(r'^sys/monkeysphere/(?P[\w]+)/publish/$', + url(r'^sys/monkeysphere/(?P[0-9A-Fa-f]+)/publish/$', views.publish, name='publish'), url(r'^sys/monkeysphere/cancel/$', views.cancel, name='cancel'), ] diff --git a/plinth/modules/monkeysphere/views.py b/plinth/modules/monkeysphere/views.py index c3184e47d..777c64b25 100644 --- a/plinth/modules/monkeysphere/views.py +++ b/plinth/modules/monkeysphere/views.py @@ -25,6 +25,7 @@ from django.shortcuts import redirect from django.template.response import TemplateResponse from django.utils.translation import ugettext as _ from django.views.decorators.http import require_POST +import json from plinth import actions from plinth import package @@ -46,19 +47,17 @@ def index(request): @require_POST -def generate(request, service): +def generate(request, domain): """Generate PGP key for SSH service.""" - for domain_type in sorted(names.get_domain_types()): - if domain_type == service: - domain = names.get_domain(domain_type) - - try: - actions.superuser_run( - 'monkeysphere', - ['host-import-ssh-key', 'ssh://' + domain]) - messages.success(request, _('Generated PGP key')) - except actions.ActionError as exception: - messages.error(request, str(exception)) + valid_domain = any((domain in domains + for domains in names.domains.values())) + if valid_domain: + try: + actions.superuser_run( + 'monkeysphere', ['host-import-ssh-key', 'ssh://' + domain]) + messages.success(request, _('Generated PGP key.')) + except actions.ActionError as exception: + messages.error(request, str(exception)) return redirect(reverse_lazy('monkeysphere:index')) @@ -81,47 +80,28 @@ def cancel(request): if publish_process: publish_process.terminate() publish_process = None - messages.info(request, _('Cancelled publish key.')) + messages.info(request, _('Cancelled key publishing.')) return redirect(reverse_lazy('monkeysphere:index')) def get_status(): """Get the current status.""" - output = actions.superuser_run('monkeysphere', ['host-show-key']) - keys = [] - for line in output.split('\n'): - data = line.strip().split() - if data and len(data) == 7: - keys.append(dict()) - keys[-1]['pub'] = data[0] - keys[-1]['date'] = data[1] - keys[-1]['uid'] = data[2] - keys[-1]['name'] = data[2].replace('ssh://', '') - keys[-1]['pgp_fingerprint'] = data[3] - keys[-1]['ssh_keysize'] = data[4] - keys[-1]['ssh_fingerprint'] = data[5] - keys[-1]['ssh_keytype'] = data[6] + output = actions.superuser_run('monkeysphere', ['host-show-keys']) + keys = {} + for key in json.loads(output)['keys']: + key['name'] = key['uid'].replace('ssh://', '') + keys[key['name']] = key - name_services = [] - for domain_type in sorted(names.get_domain_types()): - domain = names.get_domain(domain_type) - name_services.append({ - 'type': names.get_description(domain_type), - 'short_type': domain_type, - 'name': domain or _('Not Available'), - 'available': bool(domain), - 'key': None, - }) + domains = [] + for domains_of_a_type in names.domains.values(): + for domain in domains_of_a_type: + domains.append({ + 'name': domain, + 'key': keys.get(domain), + }) - # match up keys with name services - for key in keys: - for name_service in name_services: - if key['name'] == name_service['name']: - name_service['key'] = key - continue - - return {'name_services': name_services} + return {'domains': domains} def _collect_publish_result(request):