mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
configpanels: Iterating on action POC to create a certificat section in domain config panels
This commit is contained in:
parent
90e3f3235c
commit
47543b19b7
4 changed files with 116 additions and 65 deletions
|
@ -44,10 +44,10 @@ server {
|
||||||
ssl_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
|
ssl_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
|
||||||
ssl_certificate_key /etc/yunohost/certs/{{ domain }}/key.pem;
|
ssl_certificate_key /etc/yunohost/certs/{{ domain }}/key.pem;
|
||||||
|
|
||||||
{% if domain_cert_ca != "Self-signed" %}
|
{% if domain_cert_ca != "selfsigned" %}
|
||||||
more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
|
more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if domain_cert_ca == "Let's Encrypt" %}
|
{% if domain_cert_ca == "letsencrypt" %}
|
||||||
# OCSP settings
|
# OCSP settings
|
||||||
ssl_stapling on;
|
ssl_stapling on;
|
||||||
ssl_stapling_verify on;
|
ssl_stapling_verify on;
|
||||||
|
@ -99,10 +99,10 @@ server {
|
||||||
ssl_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
|
ssl_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
|
||||||
ssl_certificate_key /etc/yunohost/certs/{{ domain }}/key.pem;
|
ssl_certificate_key /etc/yunohost/certs/{{ domain }}/key.pem;
|
||||||
|
|
||||||
{% if domain_cert_ca != "Self-signed" %}
|
{% if domain_cert_ca != "selfsigned" %}
|
||||||
more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
|
more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if domain_cert_ca == "Let's Encrypt" %}
|
{% if domain_cert_ca == "letsencrypt" %}
|
||||||
# OCSP settings
|
# OCSP settings
|
||||||
ssl_stapling on;
|
ssl_stapling on;
|
||||||
ssl_stapling_verify on;
|
ssl_stapling_verify on;
|
||||||
|
|
|
@ -58,3 +58,61 @@ i18n = "domain_config"
|
||||||
# type = "number"
|
# type = "number"
|
||||||
# min = 0
|
# min = 0
|
||||||
# default = 3600
|
# default = 3600
|
||||||
|
|
||||||
|
|
||||||
|
[cert]
|
||||||
|
|
||||||
|
[cert.status]
|
||||||
|
|
||||||
|
[cert.status.cert_summary]
|
||||||
|
type = "alert"
|
||||||
|
# Automatically filled by DomainConfigPanel
|
||||||
|
|
||||||
|
[cert.status.cert_validity]
|
||||||
|
type = "number"
|
||||||
|
readonly = true
|
||||||
|
# Automatically filled by DomainConfigPanel
|
||||||
|
|
||||||
|
[cert.cert]
|
||||||
|
|
||||||
|
[cert.cert.cert_issuer]
|
||||||
|
type = "string"
|
||||||
|
readonly = true
|
||||||
|
visible = "false"
|
||||||
|
# Automatically filled by DomainConfigPanel
|
||||||
|
|
||||||
|
[cert.cert.acme_eligible]
|
||||||
|
type = "boolean"
|
||||||
|
readonly = true
|
||||||
|
visible = "false"
|
||||||
|
# Automatically filled by DomainConfigPanel
|
||||||
|
|
||||||
|
[cert.cert.acme_eligible_explain]
|
||||||
|
type = "alert"
|
||||||
|
visible = "acme_eligible == false"
|
||||||
|
# FIXME: improve messaging ...
|
||||||
|
ask = "Uhoh, domain isnt ready for ACME challenge according to the diagnosis"
|
||||||
|
|
||||||
|
[cert.cert.cert_no_checks]
|
||||||
|
ask = "Ignore diagnosis checks"
|
||||||
|
type = "boolean"
|
||||||
|
default = false
|
||||||
|
visible = "acme_eligible == false"
|
||||||
|
|
||||||
|
[cert.cert.cert_install]
|
||||||
|
ask = "Install Let's Encrypt certificate"
|
||||||
|
type = "button"
|
||||||
|
icon = "star"
|
||||||
|
style = "success"
|
||||||
|
visible = "issuer != 'letsencrypt'"
|
||||||
|
enabled = "acme_eligible or cert_no_checks"
|
||||||
|
# ??? api = "PUT /domains/{domain}/cert?force&"
|
||||||
|
|
||||||
|
[cert.cert.cert_renew]
|
||||||
|
ask = "Renew Let's Encrypt certificate"
|
||||||
|
help = "The certificate should be automatically renewed by YunoHost a few days before it expires."
|
||||||
|
type = "button"
|
||||||
|
icon = "refresh"
|
||||||
|
style = "warning"
|
||||||
|
visible = "issuer == 'letsencrypt'"
|
||||||
|
enabled = "acme_eligible or cert_no_checks"
|
||||||
|
|
|
@ -95,8 +95,6 @@ def certificate_status(domains, full=False):
|
||||||
if not full:
|
if not full:
|
||||||
del status["subject"]
|
del status["subject"]
|
||||||
del status["CA_name"]
|
del status["CA_name"]
|
||||||
status["CA_type"] = status["CA_type"]["verbose"]
|
|
||||||
status["summary"] = status["summary"]["verbose"]
|
|
||||||
|
|
||||||
if full:
|
if full:
|
||||||
try:
|
try:
|
||||||
|
@ -154,7 +152,7 @@ def _certificate_install_selfsigned(domain_list, force=False):
|
||||||
if not force and os.path.isfile(current_cert_file):
|
if not force and os.path.isfile(current_cert_file):
|
||||||
status = _get_status(domain)
|
status = _get_status(domain)
|
||||||
|
|
||||||
if status["summary"]["code"] in ("good", "great"):
|
if status["summary"] == "success":
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"certmanager_attempt_to_replace_valid_cert", domain=domain
|
"certmanager_attempt_to_replace_valid_cert", domain=domain
|
||||||
)
|
)
|
||||||
|
@ -216,7 +214,7 @@ def _certificate_install_selfsigned(domain_list, force=False):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
status
|
status
|
||||||
and status["CA_type"]["code"] == "self-signed"
|
and status["CA_type"] == "selfsigned"
|
||||||
and status["validity"] > 3648
|
and status["validity"] > 3648
|
||||||
):
|
):
|
||||||
logger.success(
|
logger.success(
|
||||||
|
@ -241,7 +239,7 @@ def _certificate_install_letsencrypt(domains, force=False, no_checks=False):
|
||||||
for domain in domain_list()["domains"]:
|
for domain in domain_list()["domains"]:
|
||||||
|
|
||||||
status = _get_status(domain)
|
status = _get_status(domain)
|
||||||
if status["CA_type"]["code"] != "self-signed":
|
if status["CA_type"] != "selfsigned":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
domains.append(domain)
|
domains.append(domain)
|
||||||
|
@ -253,7 +251,7 @@ def _certificate_install_letsencrypt(domains, force=False, no_checks=False):
|
||||||
|
|
||||||
# Is it self-signed?
|
# Is it self-signed?
|
||||||
status = _get_status(domain)
|
status = _get_status(domain)
|
||||||
if not force and status["CA_type"]["code"] != "self-signed":
|
if not force and status["CA_type"] != "selfsigned":
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"certmanager_domain_cert_not_selfsigned", domain=domain
|
"certmanager_domain_cert_not_selfsigned", domain=domain
|
||||||
)
|
)
|
||||||
|
@ -314,7 +312,7 @@ def certificate_renew(domains, force=False, no_checks=False, email=False):
|
||||||
|
|
||||||
# Does it have a Let's Encrypt cert?
|
# Does it have a Let's Encrypt cert?
|
||||||
status = _get_status(domain)
|
status = _get_status(domain)
|
||||||
if status["CA_type"]["code"] != "lets-encrypt":
|
if status["CA_type"] != "letsencrypt":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Does it expire soon?
|
# Does it expire soon?
|
||||||
|
@ -349,7 +347,7 @@ def certificate_renew(domains, force=False, no_checks=False, email=False):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Does it have a Let's Encrypt cert?
|
# Does it have a Let's Encrypt cert?
|
||||||
if status["CA_type"]["code"] != "lets-encrypt":
|
if status["CA_type"] != "letsencrypt":
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"certmanager_attempt_to_renew_nonLE_cert", domain=domain
|
"certmanager_attempt_to_renew_nonLE_cert", domain=domain
|
||||||
)
|
)
|
||||||
|
@ -539,7 +537,7 @@ def _fetch_and_enable_new_certificate(domain, no_checks=False):
|
||||||
# Check the status of the certificate is now good
|
# Check the status of the certificate is now good
|
||||||
status_summary = _get_status(domain)["summary"]
|
status_summary = _get_status(domain)["summary"]
|
||||||
|
|
||||||
if status_summary["code"] != "great":
|
if status_summary != "success":
|
||||||
raise YunohostError(
|
raise YunohostError(
|
||||||
"certmanager_certificate_fetching_or_enabling_failed", domain=domain
|
"certmanager_certificate_fetching_or_enabling_failed", domain=domain
|
||||||
)
|
)
|
||||||
|
@ -634,58 +632,25 @@ def _get_status(domain):
|
||||||
days_remaining = (valid_up_to - datetime.utcnow()).days
|
days_remaining = (valid_up_to - datetime.utcnow()).days
|
||||||
|
|
||||||
if cert_issuer in ["yunohost.org"] + yunohost.domain.domain_list()["domains"]:
|
if cert_issuer in ["yunohost.org"] + yunohost.domain.domain_list()["domains"]:
|
||||||
CA_type = {
|
CA_type = "selfsigned"
|
||||||
"code": "self-signed",
|
|
||||||
"verbose": "Self-signed",
|
|
||||||
}
|
|
||||||
|
|
||||||
elif organization_name == "Let's Encrypt":
|
elif organization_name == "Let's Encrypt":
|
||||||
CA_type = {
|
CA_type = "letsencrypt"
|
||||||
"code": "lets-encrypt",
|
|
||||||
"verbose": "Let's Encrypt",
|
|
||||||
}
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
CA_type = {
|
CA_type = "other"
|
||||||
"code": "other-unknown",
|
|
||||||
"verbose": "Other / Unknown",
|
|
||||||
}
|
|
||||||
|
|
||||||
if days_remaining <= 0:
|
if days_remaining <= 0:
|
||||||
status_summary = {
|
summary = "danger"
|
||||||
"code": "critical",
|
elif CA_type == "selfsigned":
|
||||||
"verbose": "CRITICAL",
|
summary = "warning"
|
||||||
}
|
|
||||||
|
|
||||||
elif CA_type["code"] in ("self-signed", "fake-lets-encrypt"):
|
|
||||||
status_summary = {
|
|
||||||
"code": "warning",
|
|
||||||
"verbose": "WARNING",
|
|
||||||
}
|
|
||||||
|
|
||||||
elif days_remaining < VALIDITY_LIMIT:
|
elif days_remaining < VALIDITY_LIMIT:
|
||||||
status_summary = {
|
summary = "warning"
|
||||||
"code": "attention",
|
elif CA_type == "other":
|
||||||
"verbose": "About to expire",
|
summary = "success"
|
||||||
}
|
elif CA_type == "letsencrypt":
|
||||||
|
summary = "success"
|
||||||
elif CA_type["code"] == "other-unknown":
|
|
||||||
status_summary = {
|
|
||||||
"code": "good",
|
|
||||||
"verbose": "Good",
|
|
||||||
}
|
|
||||||
|
|
||||||
elif CA_type["code"] == "lets-encrypt":
|
|
||||||
status_summary = {
|
|
||||||
"code": "great",
|
|
||||||
"verbose": "Great!",
|
|
||||||
}
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
status_summary = {
|
# shouldnt happen, because CA_type can be only selfsigned, letsencrypt, or other
|
||||||
"code": "unknown",
|
summary = ""
|
||||||
"verbose": "Unknown?",
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
|
@ -693,7 +658,7 @@ def _get_status(domain):
|
||||||
"CA_name": cert_issuer,
|
"CA_name": cert_issuer,
|
||||||
"CA_type": CA_type,
|
"CA_type": CA_type,
|
||||||
"validity": days_remaining,
|
"validity": days_remaining,
|
||||||
"summary": status_summary,
|
"summary": summary,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -499,6 +499,19 @@ class DomainConfigPanel(ConfigPanel):
|
||||||
self.registar_id = toml["dns"]["registrar"]["registrar"]["value"]
|
self.registar_id = toml["dns"]["registrar"]["registrar"]["value"]
|
||||||
del toml["dns"]["registrar"]["registrar"]["value"]
|
del toml["dns"]["registrar"]["registrar"]["value"]
|
||||||
|
|
||||||
|
# Cert stuff
|
||||||
|
if not filter_key or filter_key[0] == "cert":
|
||||||
|
|
||||||
|
from yunohost.certificate import certificate_status
|
||||||
|
status = certificate_status([self.entity], full=True)["certificates"][self.entity]
|
||||||
|
|
||||||
|
toml["cert"]["status"]["cert_summary"]["style"] = status["summary"]
|
||||||
|
# FIXME: improve message
|
||||||
|
toml["cert"]["status"]["cert_summary"]["ask"] = f"Status is {status['summary']} ! (FIXME: improve message depending on summary / issuer / validity ..."
|
||||||
|
|
||||||
|
# FIXME: Ugly hack to save the cert status and reinject it in _load_current_values ...
|
||||||
|
self.cert_status = status
|
||||||
|
|
||||||
return toml
|
return toml
|
||||||
|
|
||||||
def _load_current_values(self):
|
def _load_current_values(self):
|
||||||
|
@ -511,6 +524,21 @@ class DomainConfigPanel(ConfigPanel):
|
||||||
if not filter_key or filter_key[0] == "dns":
|
if not filter_key or filter_key[0] == "dns":
|
||||||
self.values["registrar"] = self.registar_id
|
self.values["registrar"] = self.registar_id
|
||||||
|
|
||||||
|
# FIXME: Ugly hack to save the cert status and reinject it in _load_current_values ...
|
||||||
|
if not filter_key or filter_key[0] == "cert":
|
||||||
|
self.values["cert_validity"] = self.cert_status["validity"]
|
||||||
|
self.values["cert_issuer"] = self.cert_status["CA_type"]
|
||||||
|
self.values["acme_eligible"] = self.cert_status["ACME_eligible"]
|
||||||
|
|
||||||
|
def _run_action(self, action):
|
||||||
|
|
||||||
|
if action == "cert_install":
|
||||||
|
from yunohost.certificate import certificate_install as action_func
|
||||||
|
elif action == "cert_renew":
|
||||||
|
from yunohost.certificate import certificate_renew as action_func
|
||||||
|
|
||||||
|
action_func([self.entity], force=True, no_checks=self.new_values["cert_no_checks"])
|
||||||
|
|
||||||
|
|
||||||
def _get_domain_settings(domain: str) -> dict:
|
def _get_domain_settings(domain: str) -> dict:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue