diff --git a/locales/en.json b/locales/en.json index 637671a2d..efeb66e69 100644 --- a/locales/en.json +++ b/locales/en.json @@ -254,5 +254,6 @@ "certmanager_old_letsencrypt_app_detected" : "\nYunohost detected that the 'letsencrypt' app is installed, which conflits with the new built-in certificate management features in Yunohost. If you wish to use the new built-in features, please run the following commands to migrate your installation :\n\n yunohost app remove letsencrypt\n yunohost domain cert-install\n\nN.B. : this will attempt to re-install certificates for all domains with a Let's Encrypt certificate or self-signed certificate.", "certmanager_hit_rate_limit" :"Too many certificates already issued for exact set of domains {domain:s} recently. Please try again later. See https://letsencrypt.org/docs/rate-limits/ for more details.", "certmanager_cert_signing_failed" : "Signing the new certificate failed.", - "certmanager_no_cert_file" : "Unable to read certificate file for domain {domain:s} (file : {file:s})" + "certmanager_no_cert_file" : "Unable to read certificate file for domain {domain:s} (file : {file:s})", + "certmanager_conflicting_nginx_file": "Unable to prepare domain for ACME challenge : the nginx configuration file {filepath:s} is conflicting and should be removed first." } diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py index d892e6f21..d9110b79b 100644 --- a/src/yunohost/certificate.py +++ b/src/yunohost/certificate.py @@ -32,6 +32,7 @@ import smtplib import requests import subprocess import dns.resolver +import glob from OpenSSL import crypto from datetime import datetime @@ -152,15 +153,9 @@ def certificate_install(auth, domain_list, force=False, no_checks=False, self_si def _certificate_install_selfsigned(domain_list, force=False): + for domain in domain_list: - # Check we ain't trying to overwrite a good cert ! - if (not force) : - status = _get_status(domain) - - if status["summary"]["code"] in ('good', 'great') : - raise MoulinetteError(errno.EINVAL, m18n.n('certmanager_attempt_to_replace_valid_cert', domain=domain)) - # Paths of files and folder we'll need date_tag = datetime.now().strftime("%Y%m%d.%H%M%S") new_cert_folder = "%s/%s-history/%s-selfsigned" % (CERT_FOLDER, domain, date_tag) @@ -175,6 +170,14 @@ def _certificate_install_selfsigned(domain_list, force=False): crt_file = os.path.join(new_cert_folder, "crt.pem") ca_file = os.path.join(new_cert_folder, "ca.pem") + # Check we ain't trying to overwrite a good cert ! + current_cert_file = os.path.join(CERT_FOLDER, domain, "crt.pem") + if (not force) and (os.path.isfile(current_cert_file)): + status = _get_status(domain) + + if status["summary"]["code"] in ('good', 'great') : + raise MoulinetteError(errno.EINVAL, m18n.n('certmanager_attempt_to_replace_valid_cert', domain=domain)) + # Create output folder for new certificate stuff os.makedirs(new_cert_folder) @@ -261,7 +264,7 @@ def _certificate_install_letsencrypt(auth, domain_list, force=False, no_checks=F if (staging): logger.warning("Please note that you used the --staging option, and that no new certificate will actually be enabled !") - + # Actual install steps for domain in domain_list: @@ -336,7 +339,7 @@ def certificate_renew(auth, domain_list, force=False, no_checks=False, email=Fal if (staging): logger.warning("Please note that you used the --staging option, and that no new certificate will actually be enabled !") - + # Actual renew steps for domain in domain_list: logger.info("Now attempting renewing of certificate for domain %s !", domain) @@ -421,7 +424,9 @@ Subject: %s def _configure_for_acme_challenge(auth, domain): - nginx_conf_file = "/etc/nginx/conf.d/%s.d/000-acmechallenge.conf" % domain + + nginx_conf_folder = "/etc/nginx/conf.d/%s.d" % domain + nginx_conf_file = "%s/000-acmechallenge.conf" % nginx_conf_folder nginx_configuration = ''' location '/.well-known/acme-challenge' @@ -431,6 +436,15 @@ location '/.well-known/acme-challenge' } ''' % WEBROOT_FOLDER + # Check there isn't a conflicting file for the acme-challenge well-known uri + for path in glob.glob('%s/*.conf' % nginx_conf_folder): + if (path == nginx_conf_file) : + continue + with open(path) as f: + contents = f.read() + if ('/.well-known/acme-challenge' in contents) : + raise MoulinetteError(errno.EINVAL, m18n.n('certmanager_conflicting_nginx_file', filepath=path)) + # Write the conf if os.path.exists(nginx_conf_file): logger.info("Nginx configuration file for ACME challenge already exists for domain, skipping.") @@ -564,6 +578,7 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder): def _get_status(domain): + cert_file = os.path.join(CERT_FOLDER, domain, "crt.pem") if not os.path.isfile(cert_file):