diff --git a/actions/letsencrypt b/actions/letsencrypt index c88008878..7c592bf85 100755 --- a/actions/letsencrypt +++ b/actions/letsencrypt @@ -25,6 +25,7 @@ import json import os import subprocess import sys +import re from plinth import action_utils @@ -98,6 +99,22 @@ def get_certificate_expiry(domain): return output.decode().strip().split('=')[1] +def get_validity_status(domain): + """Return validity status of a certificate, e.g. valid, revoked, expired.""" + output = subprocess.check_output(['certbot', 'certificates', '-d', domain]) + output = output.decode(sys.stdout.encoding) + + match = re.search('INVALID: (.*)\)', output) + if match is not None: + validity = match.group(1).lower() + elif re.search('VALID', output) is not None: + validity = 'valid' + else: + validity = 'unknown' + + return validity + + def subcommand_get_status(_): """Return a JSON dictionary of currently configured domains.""" try: @@ -114,7 +131,8 @@ def subcommand_get_status(_): 'certificate_available': True, 'expiry_date': get_certificate_expiry(domain), 'web_enabled': - action_utils.webserver_is_enabled(domain, kind='site') + action_utils.webserver_is_enabled(domain, kind='site'), + 'validity': get_validity_status(domain) } print(json.dumps({'domains': domain_status})) diff --git a/plinth/modules/letsencrypt/templates/letsencrypt.html b/plinth/modules/letsencrypt/templates/letsencrypt.html index e258ca2c3..52e675b67 100644 --- a/plinth/modules/letsencrypt/templates/letsencrypt.html +++ b/plinth/modules/letsencrypt/templates/letsencrypt.html @@ -51,12 +51,32 @@ {{ domain }} - {% if domain_status.certificate_available %} + {% if domain_status.certificate_available and domain_status.validity == "valid" %} {% blocktrans trimmed with expiry_date=domain_status.expiry_date %} - Expires on {{ expiry_date }} + Valid, expires on {{ expiry_date }} {% endblocktrans %} + {% elif domain_status.certificate_available and not domain_status.validity == "valid" %} + + {% if "revoked" in domain_status.validity %} + {% blocktrans trimmed %} + Revoked + {% endblocktrans %} + {% elif "expired" in domain_status.validity %} + {% blocktrans trimmed with expiry_date=domain_status.expiry_date %} + Expired on {{ expiry_date }} + {% endblocktrans %} + {% elif "test" in domain_status.validity %} + {% blocktrans trimmed %} + Invalid test certificate + {% endblocktrans %} + {% else %} + {% blocktrans trimmed with reason=domain_status.validity %} + Invalid ({{ reason }}) + {% endblocktrans %} + {% endif %} + {% else %} {% trans "No certificate" %} @@ -72,18 +92,20 @@ {% if domain_status.certificate_available %} -
- {% csrf_token %} - -
{% csrf_token %}
+ {% if "revoked" not in domain_status.validity %} +
+ {% csrf_token %} + +
+ {% endif %} {% else %}
diff --git a/plinth/modules/letsencrypt/views.py b/plinth/modules/letsencrypt/views.py index 2b51f04a3..4487c32ec 100644 --- a/plinth/modules/letsencrypt/views.py +++ b/plinth/modules/letsencrypt/views.py @@ -52,7 +52,8 @@ def revoke(request, domain): try: actions.superuser_run('letsencrypt', ['revoke', '--domain', domain]) messages.success( - request, _('Certificate successfully revoked for domain {domain}') + request, _('Certificate successfully revoked for domain {domain}.' + 'This may take a few moments to take effect.') .format(domain=domain)) except ActionError as exception: messages.error(