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..." %}
-
-
-
- {% endif %}
-
-
-
-
-
- {% trans "Service" %}
- {% trans "Domains" %}
- {% trans "OpenPGP Fingerprint" %}
-
-
-
-
- {% for key in status.keys.values|dictsort:"ssh_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 %}
-
- {% else %}
- {% if not running %}
-
- {% endif %}
- {% if key.importable_domains %}
-
- {% endif %}
- {% endif %}
-
-
- {% endfor %}
-
-
-
-
-{% 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',