From 9fd1b95244efb91ed653bce94bdfe3b509179020 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 21 Jun 2019 11:11:17 -0700 Subject: [PATCH] matrixsynapse: Add let's encrypt component for certficiates Signed-off-by: Sunil Mohan Adapa Reviewed-by: Joseph Nuthalapati --- actions/matrixsynapse | 105 ------------------ plinth/modules/matrixsynapse/__init__.py | 44 +++++++- .../templates/matrix-synapse.html | 2 +- plinth/modules/matrixsynapse/views.py | 9 +- 4 files changed, 43 insertions(+), 117 deletions(-) diff --git a/actions/matrixsynapse b/actions/matrixsynapse index 7a689bd61..1215c5a7a 100755 --- a/actions/matrixsynapse +++ b/actions/matrixsynapse @@ -20,10 +20,6 @@ Configuration helper for Matrix-Synapse server. """ import argparse -import filecmp -import os -import shutil -import sys import yaml @@ -59,67 +55,6 @@ def parse_arguments(): return parser.parse_args() -def _get_certificate_status(): - """Return if the current certificate is an up-to-date LE certificate.""" - configured_domain = get_configured_domain_name() - if not configured_domain: - return False - - if not os.path.exists(letsencrypt.LIVE_DIRECTORY): - return False - - source_dir = os.path.join(letsencrypt.LIVE_DIRECTORY, configured_domain) - source_certificate_path = os.path.join(source_dir, 'fullchain.pem') - source_private_key_path = os.path.join(source_dir, 'privkey.pem') - - dest_dir = '/etc/matrix-synapse' - dest_certificate_path = os.path.join(dest_dir, 'homeserver.tls.crt') - dest_private_key_path = os.path.join(dest_dir, 'homeserver.tls.key') - - if filecmp.cmp(source_certificate_path, dest_certificate_path) and \ - filecmp.cmp(source_private_key_path, dest_private_key_path): - return True - - return False - - -def _update_tls_certificate(): - """Update the TLS certificate and private key used by Matrix Synapse. - - A valid certificate is necessary for federation with other instances - starting with version 1.0. - - """ - configured_domain = get_configured_domain_name() - if os.path.exists(letsencrypt.LIVE_DIRECTORY) and configured_domain: - # Copy the latest Let's Encrypt certs into Synapse's directory. - src_dir = os.path.join(letsencrypt.LIVE_DIRECTORY, configured_domain) - source_certificate_path = os.path.join(src_dir, 'fullchain.pem') - source_private_key_path = os.path.join(src_dir, 'privkey.pem') - else: - # Copy Apache's snake-oil certificate into Synapse's config directory. - # The self-signed certificate doesn't really work (other Matrix - # Synapse instances do not accept it). It is merely to prevent the - # server from failing to startup because the files are missing. - source_certificate_path = '/etc/ssl/certs/ssl-cert-snakeoil.pem' - source_private_key_path = '/etc/ssl/private/ssl-cert-snakeoil.key' - - dest_dir = '/etc/matrix-synapse' - dest_certificate_path = os.path.join(dest_dir, 'homeserver.tls.crt') - dest_private_key_path = os.path.join(dest_dir, 'homeserver.tls.key') - - # Private key is only accessible to the user "matrix-synapse" - # Group access is prohibited since it is "nogroup" - old_mask = os.umask(0o133) - shutil.copyfile(source_certificate_path, dest_certificate_path) - os.umask(0o177) - shutil.copyfile(source_private_key_path, dest_private_key_path) - os.umask(old_mask) - - shutil.chown(dest_certificate_path, user='matrix-synapse', group='nogroup') - shutil.chown(dest_private_key_path, user='matrix-synapse', group='nogroup') - - def subcommand_post_install(_): """Perform post installation configuration.""" with open(CONFIG_FILE_PATH) as config_file: @@ -152,18 +87,12 @@ def subcommand_post_install(_): with open(CONFIG_FILE_PATH, 'w') as config_file: yaml.dump(config, config_file) - _update_tls_certificate() - - if action_utils.service_is_running('matrix-synapse'): - action_utils.service_restart('matrix-synapse') - def subcommand_setup(arguments): """Configure the domain name for matrix-synapse package.""" domain_name = arguments.domain_name action_utils.dpkg_reconfigure('matrix-synapse', {'server-name': domain_name}) - _update_tls_certificate() def subcommand_public_registration(argument): @@ -190,40 +119,6 @@ def subcommand_public_registration(argument): action_utils.service_restart('matrix-synapse') -def subcommand_letsencrypt(arguments): - """Add/drop usage of Let's Encrypt cert or show status. - - The command 'add' applies only to current domain, will be called by action - 'letsencrypt run_renew_hooks', when certbot renews the cert (if - matrix-synapse is selected for cert use). Drop of a cert must be possible - for any domain to respond to domain change. - - """ - if arguments.command == 'drop': - print('Dropping certificates is not supported for Matrix Synapse.') - return - - if arguments.command == 'get-status': - print('valid' if _get_certificate_status() else 'invalid') - return - - configured_domain = get_configured_domain_name() - if arguments.domain is not None and \ - arguments.domain != configured_domain: - print('Aborted: Current domain "{}" is not configured.'.format( - arguments.domain)) - sys.exit(1) - - le_folder = os.path.join(letsencrypt.LIVE_DIRECTORY, configured_domain) - if not os.path.exists(le_folder): - print('Aborted: No certificate directory at %s.' % le_folder) - sys.exit(2) - - _update_tls_certificate() - - action_utils.service_try_restart('matrix-synapse') - - def main(): arguments = parse_arguments() sub_command = arguments.subcommand.replace('-', '_') diff --git a/plinth/modules/matrixsynapse/__init__.py b/plinth/modules/matrixsynapse/__init__.py index 0db44e08a..a13c9f9a0 100644 --- a/plinth/modules/matrixsynapse/__init__.py +++ b/plinth/modules/matrixsynapse/__init__.py @@ -20,6 +20,7 @@ FreedomBox app to configure matrix-synapse server. import logging import os +import pathlib from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ @@ -31,6 +32,7 @@ from plinth import frontpage, menu from plinth.daemon import Daemon from plinth.modules.apache.components import Webserver from plinth.modules.firewall.components import Firewall +from plinth.modules.letsencrypt.components import LetsEncrypt from .manifest import backup, clients @@ -40,6 +42,8 @@ managed_services = ['matrix-synapse'] managed_packages = ['matrix-synapse', 'matrix-synapse-ldap3'] +managed_paths = [pathlib.Path('/etc/matrix-synapse/')] + name = _('Matrix Synapse') short_description = _('Chat Server') @@ -101,6 +105,16 @@ class MatrixSynapseApp(app_module.App): 'matrix-synapse-plinth') self.add(webserver) + letsencrypt = LetsEncrypt( + 'letsencrypt-matrixsynapse', domains=get_domains, daemons=[ + managed_services[0] + ], should_copy_certificates=True, + private_key_path='/etc/matrix-synapse/homeserver.tls.key', + certificate_path='/etc/matrix-synapse/homeserver.tls.crt', + user_owner='matrix-synapse', group_owner='nogroup', + managing_app='matrixsynapse') + self.add(letsencrypt) + daemon = Daemon('daemon-matrixsynapse', managed_services[0]) self.add(daemon) @@ -121,6 +135,15 @@ def setup(helper, old_version=None): helper.call('post', actions.superuser_run, 'matrixsynapse', ['post-install']) helper.call('post', app.enable) + app.get_component('letsencrypt-matrixsynapse').setup_certificates() + + +def setup_domain(domain_name): + """Configure a domain name for matrixsynapse.""" + app.get_component('letsencrypt-matrixsynapse').setup_certificates( + [domain_name]) + actions.superuser_run('matrixsynapse', + ['setup', '--domain-name', domain_name]) def is_setup(): @@ -141,6 +164,15 @@ def diagnose(): return results +def get_domains(): + """Return a list of domains this app is interested in.""" + domain = get_configured_domain_name() + if domain: + return [domain] + + return [] + + def get_configured_domain_name(): """Return the currently configured domain name.""" if not is_setup(): @@ -159,8 +191,10 @@ def get_public_registration_status(): return output.strip() == 'enabled' -def has_valid_certificate(): - """Return whether the configured domain name has a valid certificate.""" - status = actions.superuser_run('matrixsynapse', - ['letsencrypt', 'get-status']) - return status.startswith('valid') +def get_certificate_status(): + """Return the status of certificate for the configured domain.""" + status = app.get_component('letsencrypt-matrixsynapse').get_status() + if not status: + return 'no-domains' + + return list(status.values())[0] diff --git a/plinth/modules/matrixsynapse/templates/matrix-synapse.html b/plinth/modules/matrixsynapse/templates/matrix-synapse.html index c157394b2..1cc7121b2 100644 --- a/plinth/modules/matrixsynapse/templates/matrix-synapse.html +++ b/plinth/modules/matrixsynapse/templates/matrix-synapse.html @@ -39,7 +39,7 @@ {% endblocktrans %}

- {% if not has_valid_certificate %} + {% if certificate_status != "valid" %}