From ce5274d9ee3bc52a3cb5a00cf3d6b7cfeaa1be59 Mon Sep 17 00:00:00 2001 From: Joseph Nuthalapati Date: Sat, 11 Dec 2021 11:50:09 +0530 Subject: [PATCH] monkeysphere: Drop app as it is not being used Closes #2157. Signed-off-by: Joseph Nuthalapati [sunil: Split diaspora and tahoe-lafs into separate commits] [sunil: Remove monkeysphere from help/tests/test_views.py] [sunil: Add to configuration file removal in Debian package and setup.py] Signed-off-by: Sunil Mohan Adapa Reviewed-by: Sunil Mohan Adapa --- actions/monkeysphere | 318 ------------------ debian/freedombox.maintscript | 1 + plinth/modules/help/tests/test_views.py | 21 +- plinth/modules/monkeysphere/__init__.py | 74 ---- .../etc/plinth/modules-enabled/monkeysphere | 1 - plinth/modules/monkeysphere/manifest.py | 13 - .../monkeysphere/static/monkeysphere.css | 20 -- .../monkeysphere/templates/monkeysphere.html | 136 -------- .../templates/monkeysphere_details.html | 85 ----- plinth/modules/monkeysphere/tests/__init__.py | 0 .../monkeysphere/tests/test_functional.py | 100 ------ plinth/modules/monkeysphere/urls.py | 19 -- plinth/modules/monkeysphere/views.py | 135 -------- plinth/tests/functional/__init__.py | 6 +- pyproject.toml | 1 - setup.py | 1 + 16 files changed, 15 insertions(+), 916 deletions(-) delete mode 100755 actions/monkeysphere delete mode 100644 plinth/modules/monkeysphere/__init__.py delete mode 100644 plinth/modules/monkeysphere/data/etc/plinth/modules-enabled/monkeysphere delete mode 100644 plinth/modules/monkeysphere/manifest.py delete mode 100644 plinth/modules/monkeysphere/static/monkeysphere.css delete mode 100644 plinth/modules/monkeysphere/templates/monkeysphere.html delete mode 100644 plinth/modules/monkeysphere/templates/monkeysphere_details.html delete mode 100644 plinth/modules/monkeysphere/tests/__init__.py delete mode 100644 plinth/modules/monkeysphere/tests/test_functional.py delete mode 100644 plinth/modules/monkeysphere/urls.py delete mode 100644 plinth/modules/monkeysphere/views.py diff --git a/actions/monkeysphere b/actions/monkeysphere deleted file mode 100755 index e9c892a7e..000000000 --- a/actions/monkeysphere +++ /dev/null @@ -1,318 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for monkeysphere. -""" - -import argparse -import contextlib -import copy -import json -import os -import re -import shutil -import signal -import subprocess -import tempfile - -import augeas -import psutil - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - host_show_keys = subparsers.add_parser( - 'host-show-keys', help='Show imported/importable keys') - host_show_keys.add_argument('key_id', nargs='?', - help='Optional KEYID to retrieve details for') - - host_import_key = subparsers.add_parser( - 'host-import-key', help='Import a key into monkeysphere') - host_import_key.add_argument('ssh_fingerprint', - help='SSH fingerprint of the key to import') - host_import_key.add_argument('domains', nargs='*', - help='List of available domains') - - host_publish_key = subparsers.add_parser('host-publish-key', - help='Push host key to keyserver') - host_publish_key.add_argument('key_ids', nargs='*', - help='Optional list of KEYIDs') - - host_cancel_publish = subparsers.add_parser( - 'host-cancel-publish', help='Cancel a running publish operation') - host_cancel_publish.add_argument('pid', help='PID of the publish process') - - subparsers.required = True - return parser.parse_args() - - -def get_ssh_keys(fingerprint_hash): - """Return all SSH keys.""" - keys = {} - - key_files = ['/etc/ssh/ssh_host_rsa_key'] - for key_file in key_files: - output = subprocess.check_output( - ['ssh-keygen', '-l', '-E', fingerprint_hash, '-f', key_file]) - fingerprint = output.decode().split()[1] - keys[fingerprint] = { - 'ssh_fingerprint': fingerprint, - 'service': 'ssh', - 'key_file': key_file, - 'available_domains': ['*'] - } - - return keys - - -def get_pem_ssh_fingerprint(pem_file, fingerprint_hash): - """Return the SSH fingerprint of a PEM file.""" - public_key = subprocess.check_output( - ['openssl', 'rsa', '-in', pem_file, '-pubout'], - stderr=subprocess.DEVNULL) - ssh_public_key = subprocess.check_output( - ['ssh-keygen', '-i', '-m', 'PKCS8', '-f', '/dev/stdin'], - input=public_key) - fingerprint = subprocess.check_output( - ['ssh-keygen', '-l', '-E', fingerprint_hash, '-f', '/dev/stdin'], - input=ssh_public_key) - - return fingerprint.decode().split()[1] - - -def get_https_keys(fingerprint_hash): - """Return all HTTPS keys.""" - aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + - augeas.Augeas.NO_MODL_AUTOLOAD) - aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') - aug.set('/augeas/load/Httpd/incl[last() + 1]', - '/etc/apache2/sites-available/*') - aug.set('/augeas/load/Httpd/incl[last() + 1]', - '/etc/apache2/conf-available/*') - aug.load() - - # Read from default-tls.conf and default-ssl.conf - keys = {} - path = '/files/etc/apache2/sites-available//VirtualHost' - for match in aug.match(path): - host = {'available_domains': ['*'], 'service': 'https'} - for directive in aug.match(match + '/directive'): - name = aug.get(directive) - if name == 'ServerName': - host['available_domains'] = [aug.get(directive + '/arg')] - elif name in ('GnuTLSKeyFile', 'SSLCertificateKeyFile'): - host['key_file'] = aug.get(directive + '/arg') - - if 'key_file' in host: - host['ssh_fingerprint'] = get_pem_ssh_fingerprint( - host['key_file'], fingerprint_hash) - keys[host['ssh_fingerprint']] = host - - # Read from FreedomBox configured domains with proper SSL certs. - path = "/files/etc/apache2/sites-available//" \ - "directive[. = 'Use'][arg[1] = 'FreedomBoxTLSSiteMacro']" - key_file = ("/files/etc/apache2//Macro[arg[1] = 'FreedomBoxTLSSiteMacro']" - "//VirtualHost/directive[. = 'GnuTLSKeyFile']/arg") - key_file = aug.get(key_file) - for match in aug.match(path): - domain = aug.get(match + '/arg[2]') - host = { - 'available_domains': [domain], - 'service': 'https', - 'key_file': key_file.replace('$domain', domain) - } - host['ssh_fingerprint'] = get_pem_ssh_fingerprint( - host['key_file'], fingerprint_hash) - keys[host['ssh_fingerprint']] = host - - return keys - - -def get_monkeysphere_keys(key_id=None): - """Return the list of keys imported into monkeysphere.""" - try: - key_ids = [] if not key_id else [key_id] - output = subprocess.check_output(['monkeysphere-host', 'show-keys'] + - key_ids, stderr=subprocess.DEVNULL) - except subprocess.CalledProcessError: - # no keys available - return {} - - # parse output - default_dict = {'imported_domains': [], 'available_domains': []} - keys = [copy.deepcopy(default_dict)] - lines = output.decode().strip().split('\n') - for line in lines: - if line.startswith('pub'): - data = line.lstrip('pub').split() - keys[-1]['pub'] = data[0] - keys[-1]['date'] = data[1] - elif line.startswith('uid'): - uid = line.lstrip('uid').strip() - if uid.startswith('['): - uid = uid[uid.index(']') + 1:].strip() - - keys[-1].setdefault('uids', []).append(uid) - matches = re.match(r'([a-zA-Z]*)://(.*)(:\d*)?', uid) - keys[-1]['service'] = matches.group(1) - keys[-1]['imported_domains'].append(matches.group(2)) - elif line.startswith('OpenPGP fingerprint:'): - keys[-1]['openpgp_fingerprint'] = \ - line.lstrip('OpenPGP fingerprint:') - elif line.startswith('ssh fingerprint:'): - data = line.lstrip('ssh fingerprint:').split() - keys[-1]['ssh_key_size'] = data[0] - keys[-1]['ssh_fingerprint'] = data[1] - keys[-1]['ssh_key_type'] = data[2].strip('()') - elif line == '': - keys.append(copy.deepcopy(default_dict)) - - return {key['ssh_fingerprint']: key for key in keys} - - -def get_merged_keys(key_id=None): - """Return merged list of system and monkeysphere keys.""" - keys = get_monkeysphere_keys(key_id) - - # Monkeysphere used use MD5 for fingerprint hash and recently - # changed to SHA256. In case of SHA256 the string 'SHA256:' is - # being prepended to the fingerprint. Hoping that such a prefix - # will be available in all future changes, extract it from one key - # (assuming all the others will be the same) and use it. - fingerprint_hash = 'SHA256' - if keys: - fingerprint_hash = list(keys.keys())[0].split(':')[0] - - system_keys = list(get_ssh_keys(fingerprint_hash).items()) + \ - list(get_https_keys(fingerprint_hash).items()) - for ssh_fingerprint, key in system_keys: - if key_id and ssh_fingerprint not in keys: - continue - - if ssh_fingerprint in keys: - keys[ssh_fingerprint].update({ - 'available_domains': key['available_domains'], - 'key_file': key['key_file'] - }) - else: - keys[ssh_fingerprint] = key - - return keys - - -@contextlib.contextmanager -def _get_ssh_key_file_for_import(original_key_file, service): - """Return an SSH key file that can be imported into monkeysphere. - - If the key file is in PEM format, the key file can be used as it is. - Otherwise, if the file is in the OpenSSH key format, which is default since - 7.8, then convert it to PEM format. - - """ - if service != 'ssh': - yield original_key_file - return - - first_line = open(original_key_file, 'r').readline() - if '--BEGIN OPENSSH PRIVATE KEY--' not in first_line: - yield original_key_file - return - - with tempfile.TemporaryDirectory() as temp_directory: - key_file = os.path.join(temp_directory, 'ssh_key_file') - shutil.copy2(original_key_file, key_file) - # Convert OpenSSH format to PEM - subprocess.run( - ['ssh-keygen', '-p', '-N', '', '-m', 'PEM', '-f', key_file], - check=True) - yield key_file - - -def subcommand_host_show_keys(arguments): - """Show host key fingerprints.""" - print(json.dumps({'keys': get_merged_keys(arguments.key_id)})) - - -def subcommand_host_import_key(arguments, second_run=False): - """Import host SSH key.""" - keys = get_merged_keys() - if arguments.ssh_fingerprint not in keys: - raise Exception('Unknown SSH fingerprint') - - key = keys[arguments.ssh_fingerprint] - if '*' in key['available_domains']: - key['available_domains'] = arguments.domains - - if 'openpgp_fingerprint' not in key and not second_run: - env = dict(os.environ, MONKEYSPHERE_PROMPT='false') - with _get_ssh_key_file_for_import(key['key_file'], - key['service']) as key_file: - subprocess.check_call([ - 'monkeysphere-host', 'import-key', key_file, - key['service'] + '://' + key['available_domains'][0] - ], env=env) - - subcommand_host_import_key(arguments, second_run=True) - else: - for domain in key['available_domains']: - if domain in key['imported_domains']: - continue - - env = dict(os.environ, MONKEYSPHERE_PROMPT='false') - subprocess.check_call([ - 'monkeysphere-host', 'add-servicename', - key['service'] + '://' + domain, key['openpgp_fingerprint'] - ], env=env) - - -def subcommand_host_publish_key(arguments): - """Push host key to keyserver.""" - # setting TMPDIR as workaround for Debian bug #656750 - proc = subprocess.Popen( - ['monkeysphere-host', 'publish-keys'] + arguments.key_ids, - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=dict(os.environ, - TMPDIR='/var/lib/monkeysphere/authentication/tmp/', - MONKEYSPHERE_PROMPT='false')) - output, error = proc.communicate() - output, error = output.decode(), error.decode() - if proc.returncode != 0: - raise Exception(output, error) - - print(output) - - -def subcommand_host_cancel_publish(arguments): - """Kill a running publish process.""" - process = psutil.Process(int(arguments.pid)) - - # Perform tight checks on the process before killing for security. - arguments = process.cmdline() - if not arguments: - # Process already completed - return - - # Remove the sudo prefix if present - while arguments[0] == 'sudo' or arguments[0].startswith('-'): - arguments = arguments[1:] - - if len(arguments) >= 2 and \ - arguments[0].split('/')[-1] == 'monkeysphere' and \ - arguments[1] == 'host-publish-key': - process.send_signal(signal.SIGTERM) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/debian/freedombox.maintscript b/debian/freedombox.maintscript index d9b3a7b5e..943a06034 100644 --- a/debian/freedombox.maintscript +++ b/debian/freedombox.maintscript @@ -13,3 +13,4 @@ rm_conffile /etc/apt/preferences.d/50freedombox3.pref 20.5~ rm_conffile /etc/plinth/plinth.config 20.12~ rm_conffile /etc/plinth/custom-shortcuts.json 20.12~ rm_conffile /etc/plinth/modules-enabled/coquelicot 20.14~ +rm_conffile /etc/plinth/modules-enabled/monkeysphere 21.16~ diff --git a/plinth/modules/help/tests/test_views.py b/plinth/modules/help/tests/test_views.py index 3ab4c53ab..331ab07d9 100644 --- a/plinth/modules/help/tests/test_views.py +++ b/plinth/modules/help/tests/test_views.py @@ -109,17 +109,16 @@ MANUAL_PAGES = ('Apache_userdir', 'APU', 'Backups', 'BananaPro', 'BeagleBone', 'freedombox-manual', 'GettingHelp', 'GitWeb', 'Hardware', 'I2P', 'Ikiwiki', 'Infinoted', 'Introduction', 'JSXC', 'LetsEncrypt', 'Maker', 'MatrixSynapse', 'MediaWiki', - 'Minetest', 'MiniDLNA', 'MLDonkey', 'Monkeysphere', 'Mumble', - 'NameServices', 'Networks', 'OpenVPN', 'OrangePiZero', - 'PageKite', 'pcDuino3', 'Performance', 'PineA64+', - 'PioneerEdition', 'Plinth', 'Power', 'Privoxy', 'Quassel', - 'QuickStart', 'Radicale', 'RaspberryPi2', 'RaspberryPi3B+', - 'RaspberryPi3B', 'RaspberryPi4B', 'ReleaseNotes', 'Rock64', - 'RockPro64', 'Roundcube', 'Samba', 'Searx', 'SecureShell', - 'Security', 'ServiceDiscovery', 'Shadowsocks', 'Sharing', - 'Snapshots', 'Storage', 'Syncthing', 'TinyTinyRSS', 'Tor', - 'Transmission', 'Upgrades', 'USBWiFi', 'Users', 'VirtualBox', - 'WireGuard') + 'Minetest', 'MiniDLNA', 'MLDonkey', 'Mumble', 'NameServices', + 'Networks', 'OpenVPN', 'OrangePiZero', 'PageKite', 'pcDuino3', + 'Performance', 'PineA64+', 'PioneerEdition', 'Plinth', 'Power', + 'Privoxy', 'Quassel', 'QuickStart', 'Radicale', 'RaspberryPi2', + 'RaspberryPi3B+', 'RaspberryPi3B', 'RaspberryPi4B', + 'ReleaseNotes', 'Rock64', 'RockPro64', 'Roundcube', 'Samba', + 'Searx', 'SecureShell', 'Security', 'ServiceDiscovery', + 'Shadowsocks', 'Sharing', 'Snapshots', 'Storage', 'Syncthing', + 'TinyTinyRSS', 'Tor', 'Transmission', 'Upgrades', 'USBWiFi', + 'Users', 'VirtualBox', 'WireGuard') _restricted_reason = ('Needs installed manual. ' 'CI speed-optimized workspace does not provide it.') not_restricted_environment = pytest.mark.skipif(not canary.exists(), diff --git a/plinth/modules/monkeysphere/__init__.py b/plinth/modules/monkeysphere/__init__.py deleted file mode 100644 index c6aea2286..000000000 --- a/plinth/modules/monkeysphere/__init__.py +++ /dev/null @@ -1,74 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for monkeysphere. -""" - -from django.utils.translation import gettext_lazy as _ - -from plinth import app as app_module -from plinth import menu -from plinth.modules.backups.components import BackupRestore -from plinth.modules.users.components import UsersAndGroups -from plinth.package import Packages - -from . import manifest - -_description = [ - _('With Monkeysphere, an OpenPGP key can be generated for each configured ' - 'domain serving SSH. The OpenPGP public key can then be uploaded to the ' - 'OpenPGP 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 OpenPGP key signing process. See the ' - ' ' - 'Monkeysphere SSH documentation for more details.'), - _('Monkeysphere can also generate an OpenPGP key for each Secure Web ' - 'Server (HTTPS) certificate installed on this machine. The OpenPGP ' - 'public key can then be uploaded to the OpenPGP keyservers. Users ' - 'accessing the web server through HTTPS can verify that they are ' - 'connecting to the correct host. To validate the certificate, the user ' - 'will need to install some software that is available on the ' - ' Monkeysphere ' - 'website.') -] - -app = None - - -class MonkeysphereApp(app_module.App): - """FreedomBox app for Monkeysphere.""" - - app_id = 'monkeysphere' - - _version = 1 - - def __init__(self): - """Create components for the app.""" - super().__init__() - - info = app_module.Info(app_id=self.app_id, version=self._version, - name=_('Monkeysphere'), icon='fa-certificate', - description=_description, - manual_page='Monkeysphere') - self.add(info) - - menu_item = menu.Menu('menu-monkeysphere', info.name, None, info.icon, - 'monkeysphere:index', parent_url_name='system', - advanced=True) - self.add(menu_item) - - packages = Packages('packages-monkeysphere', ['monkeysphere']) - self.add(packages) - - users_and_groups = UsersAndGroups('users-and-groups-monkeysphere', - reserved_usernames=['monkeysphere']) - self.add(users_and_groups) - - backup_restore = BackupRestore('backup-restore-monkeysphere', - **manifest.backup) - self.add(backup_restore) - - -def setup(helper, old_version=None): - """Install and configure the module.""" - app.setup(old_version) diff --git a/plinth/modules/monkeysphere/data/etc/plinth/modules-enabled/monkeysphere b/plinth/modules/monkeysphere/data/etc/plinth/modules-enabled/monkeysphere deleted file mode 100644 index 2de664397..000000000 --- a/plinth/modules/monkeysphere/data/etc/plinth/modules-enabled/monkeysphere +++ /dev/null @@ -1 +0,0 @@ -plinth.modules.monkeysphere diff --git a/plinth/modules/monkeysphere/manifest.py b/plinth/modules/monkeysphere/manifest.py deleted file mode 100644 index 0f5708de6..000000000 --- a/plinth/modules/monkeysphere/manifest.py +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Application manfiest for monkeysphere. -""" - -backup = { - 'config': { - 'directories': ['/etc/monkeysphere/'] - }, - 'secrets': { - 'directories': ['/var/lib/monkeysphere/'] - } -} diff --git a/plinth/modules/monkeysphere/static/monkeysphere.css b/plinth/modules/monkeysphere/static/monkeysphere.css deleted file mode 100644 index 323f40788..000000000 --- a/plinth/modules/monkeysphere/static/monkeysphere.css +++ /dev/null @@ -1,20 +0,0 @@ -/* -# SPDX-License-Identifier: AGPL-3.0-or-later -*/ - -td li { - list-style: none; - line-height: 2rem; -} - -td ul { - padding: 0; -} - -.form-action.pull-right { - margin-right: 0.625rem; -} - -.form-action button { - width: 7.875rem; -} diff --git a/plinth/modules/monkeysphere/templates/monkeysphere.html b/plinth/modules/monkeysphere/templates/monkeysphere.html deleted file mode 100644 index f74d2f132..000000000 --- a/plinth/modules/monkeysphere/templates/monkeysphere.html +++ /dev/null @@ -1,136 +0,0 @@ -{% extends "app.html" %} -{% comment %} -# SPDX-License-Identifier: AGPL-3.0-or-later -{% endcomment %} - -{% load bootstrap %} -{% load i18n %} -{% load static %} - -{% block page_head %} - -{% endblock %} - -{% block configuration %} - - {% if running %} -

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

- {% csrf_token %} - - -
-

- {% endif %} - -
- - - - - - - - - - - {% for key in status.keys.values|dictsort:"ssh_fingerprint" %} - - - - - - - {% endfor %} - -
{% trans "Service" %}{% trans "Domains" %}{% trans "OpenPGP Fingerprint" %}
- {% if key.service == 'ssh' %} - {% trans "Secure Shell" %} - {% elif key.service == 'https' %} - {% trans "Web Server" %} - {% else %} - {% trans "Other" %} - {% endif %} - -
    - {% for domain in key.all_domains %} - {% if domain not in key.imported_domains %} -
  • - - {{ domain }} -
  • - {% elif domain not in key.available_domains %} -
  • - - {{ domain }} -
  • - {% else %} -
  • - - {{ domain }} -
  • - {% endif %} - {% endfor %} -
-
- {% if key.openpgp_fingerprint %} - - {{ key.openpgp_fingerprint }} - - {% else %} - {% trans "-" %} - {% endif %} - - {% if not key.openpgp_fingerprint %} -
- {% csrf_token %} - - -
- {% else %} - {% if not running %} -
- {% csrf_token %} - - -
- {% endif %} - {% if key.importable_domains %} -
- {% csrf_token %} - - -
- {% endif %} - {% endif %} -
-
- -{% endblock %} diff --git a/plinth/modules/monkeysphere/templates/monkeysphere_details.html b/plinth/modules/monkeysphere/templates/monkeysphere_details.html deleted file mode 100644 index d3a74ffd1..000000000 --- a/plinth/modules/monkeysphere/templates/monkeysphere_details.html +++ /dev/null @@ -1,85 +0,0 @@ -{% extends "base.html" %} -{% comment %} -# SPDX-License-Identifier: AGPL-3.0-or-later -{% endcomment %} - -{% load bootstrap %} -{% load i18n %} - -{% block content %} - -

{% trans "Monkeysphere" %}

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{% trans "OpenPGP Fingerprint" %}{{ key.openpgp_fingerprint }}
{% trans "OpenPGP User IDs" %}{{ key.uids|join:', ' }}
{% trans "Key Import Date" %}{{ key.date }}
{% trans "SSH Key Type" %}{{ key.ssh_key_type }}
{% trans "SSH Key Size" %}{{ key.ssh_key_size }}
{% trans "SSH Fingerprint" %}{{ key.ssh_fingerprint }}
{% trans "Service" %} - {% if key.service == 'ssh' %} - {% trans "Secure Shell" %} - {% elif key.service == 'https' %} - {% trans "Web Server" %} - {% else %} - {% trans "Other" %} - {% endif %} -
{% trans "Key File" %}{{ key.key_file }}
{% trans "Available Domains" %}{{ key.available_domains|join:', ' }}
{% trans "Added Domains" %}{{ key.imported_domains|join:', ' }}
-
- -

- {% blocktrans trimmed %} - After this key is published to the keyservers, it can be signed using - GnuPG with the following commands: - {% endblocktrans %} -

-
-# {% trans "Download the key" %}
-gpg --recv-key {{ key.openpgp_fingerprint }}
-
-# {% trans "Sign the key" %}
-gpg --sign-key {{ key.openpgp_fingerprint }}
-
-# {% trans "Send the key back to the keyservers" %}
-gpg --send-key {{ key.openpgp_fingerprint }}
-
- -{% endblock %} diff --git a/plinth/modules/monkeysphere/tests/__init__.py b/plinth/modules/monkeysphere/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/plinth/modules/monkeysphere/tests/test_functional.py b/plinth/modules/monkeysphere/tests/test_functional.py deleted file mode 100644 index bd59df726..000000000 --- a/plinth/modules/monkeysphere/tests/test_functional.py +++ /dev/null @@ -1,100 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Functional, browser based tests for monkeysphere app. -""" - -import pytest -from plinth.tests import functional - -pytestmark = [pytest.mark.system, pytest.mark.monkeysphere] - - -@pytest.fixture(scope='module', autouse=True) -def fixture_background(session_browser): - """Login and install the app.""" - functional.login(session_browser) - functional.set_advanced_mode(session_browser, True) - functional.install(session_browser, 'monkeysphere') - functional.set_domain_name(session_browser, 'mydomain.example') - yield - - -def test_import_ssh_keys(session_browser): - """Test importing SSH keys.""" - _import_key(session_browser, 'ssh', 'mydomain.example') - _assert_imported_key(session_browser, 'ssh', 'mydomain.example') - - -def test_import_https_keys(session_browser): - """Test importing HTTPS keys.""" - _import_key(session_browser, 'https', 'mydomain.example') - _assert_imported_key(session_browser, 'https', 'mydomain.example') - - -def test_publish_ssh_keys(session_browser): - """Test publishing SSH keys.""" - _import_key(session_browser, 'ssh', 'mydomain.example') - _publish_key(session_browser, 'ssh', 'mydomain.example') - - -def test_publish_https_keys(session_browser): - """Test publishing HTTPS keys.""" - _import_key(session_browser, 'https', 'mydomain.example') - _publish_key(session_browser, 'https', 'mydomain.example') - - -def test_backup_restore(session_browser): - """Test backup and restore of keys""" - _import_key(session_browser, 'ssh', 'mydomain.example') - _import_key(session_browser, 'https', 'mydomain.example') - functional.backup_create(session_browser, 'monkeysphere', - 'test_monkeysphere') - - functional.backup_restore(session_browser, 'monkeysphere', - 'test_monkeysphere') - _assert_imported_key(session_browser, 'ssh', 'mydomain.example') - _assert_imported_key(session_browser, 'https', 'mydomain.example') - - -def _find_domain(browser, key_type, domain_type, domain): - """Iterate every domain of a given type which given key type.""" - keys_of_type = browser.find_by_css( - '.monkeysphere-service-{}'.format(key_type)) - for key_of_type in keys_of_type: - search_domains = key_of_type.find_by_css( - '.monkeysphere-{}-domain'.format(domain_type)) - for search_domain in search_domains: - if search_domain.text == domain: - return key_of_type, search_domain - - raise IndexError('Domain not found') - - -def _import_key(browser, key_type, domain): - """Import a key of specified type for given domain into monkeysphere.""" - try: - _assert_imported_key(browser, key_type, domain) - except IndexError: - pass - else: - return - - key, _ = _find_domain(browser, key_type, 'importable', domain) - with functional.wait_for_page_update(browser): - key.find_by_css('.button-import').click() - - -def _assert_imported_key(browser, key_type, domain): - """Assert that a key of specified type for given domain was imported..""" - functional.nav_to_module(browser, 'monkeysphere') - return _find_domain(browser, key_type, 'imported', domain) - - -def _publish_key(browser, key_type, domain): - """Publish a key of specified type for given domain from monkeysphere.""" - functional.nav_to_module(browser, 'monkeysphere') - key, _ = _find_domain(browser, key_type, 'imported', domain) - with functional.wait_for_page_update(browser): - key.find_by_css('.button-publish').click() - - functional.wait_for_config_update(browser, 'monkeysphere') diff --git a/plinth/modules/monkeysphere/urls.py b/plinth/modules/monkeysphere/urls.py deleted file mode 100644 index 68e1cb215..000000000 --- a/plinth/modules/monkeysphere/urls.py +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -URLs for the monkeysphere module. -""" - -from django.urls import re_path - -from . import views - -urlpatterns = [ - re_path(r'^sys/monkeysphere/$', views.index, name='index'), - re_path(r'^sys/monkeysphere/(?P[0-9A-Za-z:+/]+)/import/$', - views.import_key, name='import'), - re_path(r'^sys/monkeysphere/(?P[0-9A-Fa-f]+)/details/$', - views.details, name='details'), - re_path(r'^sys/monkeysphere/(?P[0-9A-Fa-f]+)/publish/$', - views.publish, name='publish'), - re_path(r'^sys/monkeysphere/cancel/$', views.cancel, name='cancel'), -] diff --git a/plinth/modules/monkeysphere/views.py b/plinth/modules/monkeysphere/views.py deleted file mode 100644 index 27c3c22a9..000000000 --- a/plinth/modules/monkeysphere/views.py +++ /dev/null @@ -1,135 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for the monkeysphere module. -""" - -import json - -from django.contrib import messages -from django.shortcuts import redirect -from django.template.response import TemplateResponse -from django.urls import reverse_lazy -from django.utils.translation import gettext as _ -from django.views.decorators.http import require_POST - -from plinth import actions -from plinth.modules import monkeysphere, names - -publish_process = None - - -def index(request): - """Serve configuration page.""" - _collect_publish_result(request) - status = get_status() - return TemplateResponse( - request, 'monkeysphere.html', { - 'app_info': monkeysphere.app.info, - 'title': monkeysphere.app.info.name, - 'status': status, - 'running': bool(publish_process), - 'refresh_page_sec': 3 if bool(publish_process) else None, - }) - - -@require_POST -def import_key(request, ssh_fingerprint): - """Import a key into monkeysphere.""" - keys = get_keys() - available_domains = keys[ssh_fingerprint]['available_domains'] - try: - actions.superuser_run('monkeysphere', - ['host-import-key', ssh_fingerprint] + - list(available_domains)) - messages.success(request, _('Imported key.')) - except actions.ActionError as exception: - messages.error(request, str(exception)) - - return redirect(reverse_lazy('monkeysphere:index')) - - -def details(request, fingerprint): - """Get details for an OpenPGP key.""" - return TemplateResponse(request, 'monkeysphere_details.html', { - 'title': monkeysphere.app.info.name, - 'key': get_key(fingerprint) - }) - - -@require_POST -def publish(request, fingerprint): - """Publish OpenPGP key for SSH service.""" - global publish_process - if not publish_process: - publish_process = actions.superuser_run( - 'monkeysphere', ['host-publish-key', fingerprint], - run_in_background=True) - - return redirect(reverse_lazy('monkeysphere:index')) - - -@require_POST -def cancel(request): - """Cancel ongoing process.""" - global publish_process - if publish_process: - actions.superuser_run( - 'monkeysphere', ['host-cancel-publish', - str(publish_process.pid)]) - publish_process = None - messages.info(request, _('Cancelled key publishing.')) - - return redirect(reverse_lazy('monkeysphere:index')) - - -def get_status(): - """Get the current status.""" - return {'keys': get_keys()} - - -def get_keys(fingerprint=None): - """Get keys.""" - fingerprint = [fingerprint] if fingerprint else [] - output = actions.superuser_run('monkeysphere', - ['host-show-keys'] + fingerprint) - keys = json.loads(output)['keys'] - - domains = names.components.DomainName.list_names() - for key in keys.values(): - key['imported_domains'] = set(key.get('imported_domains', [])) - key['available_domains'] = set(key.get('available_domains', [])) - if '*' in key['available_domains']: - key['available_domains'] = set(domains) - - key['all_domains'] = sorted(key['available_domains'].union( - key['imported_domains'])) - key['importable_domains'] = key['available_domains'] \ - .difference(key['imported_domains']) - - return keys - - -def get_key(fingerprint): - """Get key by fingerprint.""" - keys = get_keys(fingerprint) - return list(keys.values())[0] if len(keys) else None - - -def _collect_publish_result(request): - """Handle publish process completion.""" - global publish_process - if not publish_process: - return - - return_code = publish_process.poll() - - # Publish process is not complete yet - if return_code is None: - return - - if not return_code: - messages.success(request, _('Published key to keyserver.')) - else: - messages.error(request, _('Error occurred while publishing key.')) - - publish_process = None diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index 10e6511a9..f5738a137 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -50,9 +50,9 @@ _site_url = { _sys_modules = [ 'avahi', 'backups', 'bind', 'cockpit', 'config', 'datetime', 'diagnostics', - 'dynamicdns', 'firewall', 'letsencrypt', 'monkeysphere', 'names', - 'networks', 'pagekite', 'performance', 'power', 'security', 'snapshot', - 'ssh', 'storage', 'upgrades', 'users' + 'dynamicdns', 'firewall', 'letsencrypt', 'names', 'networks', 'pagekite', + 'performance', 'power', 'security', 'snapshot', 'ssh', 'storage', + 'upgrades', 'users' ] diff --git a/pyproject.toml b/pyproject.toml index 2c77234ca..d0d36c748 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,6 @@ markers = [ "minetest", "minidlna", "mldonkey", - "monkeysphere", "mumble", "openvpn", "pagekite", diff --git a/setup.py b/setup.py index 52e46fd7f..2d82edf1d 100755 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ DISABLED_APPS_TO_REMOVE = [ 'apps', 'coquelicot', 'diaspora', + 'monkeysphere', 'owncloud', 'system', 'xmpp',