mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2024-11-22 02:17:26 +00:00
show SSL certificate expiration info in the control panel even long before certificates expire
This commit is contained in:
parent
20892b5d5b
commit
7d1c0b3834
@ -108,7 +108,7 @@ def buy_ssl_certificate(api_key, domain, command, env):
|
|||||||
|
|
||||||
# Check before we overwrite something we shouldn't.
|
# Check before we overwrite something we shouldn't.
|
||||||
if os.path.exists(ssl_certificate):
|
if os.path.exists(ssl_certificate):
|
||||||
cert_status = check_certificate(None, ssl_certificate, None)
|
cert_status, cert_status_details = check_certificate(None, ssl_certificate, None)
|
||||||
if cert_status != "SELF-SIGNED":
|
if cert_status != "SELF-SIGNED":
|
||||||
print("Please back up and delete the file %s so I can save your new certificate." % ssl_certificate)
|
print("Please back up and delete the file %s so I can save your new certificate." % ssl_certificate)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -360,9 +360,15 @@ def check_ssl_cert(domain, env):
|
|||||||
|
|
||||||
# Check that the certificate is good.
|
# Check that the certificate is good.
|
||||||
|
|
||||||
cert_status = check_certificate(domain, ssl_certificate, ssl_key)
|
cert_status, cert_status_details = check_certificate(domain, ssl_certificate, ssl_key)
|
||||||
|
|
||||||
|
if cert_status == "OK":
|
||||||
|
# The certificate is ok. The details has expiry info.
|
||||||
|
env['out'].print_ok("SSL certificate is signed & valid. " + cert_status_details)
|
||||||
|
|
||||||
|
elif cert_status == "SELF-SIGNED":
|
||||||
|
# Offer instructions for purchasing a signed certificate.
|
||||||
|
|
||||||
if cert_status == "SELF-SIGNED":
|
|
||||||
fingerprint = shell('check_output', [
|
fingerprint = shell('check_output', [
|
||||||
"openssl",
|
"openssl",
|
||||||
"x509",
|
"x509",
|
||||||
@ -393,13 +399,11 @@ def check_ssl_cert(domain, env):
|
|||||||
If you receive intermediate certificates, use a text editor and paste your certificate on top and then the intermediate certificates
|
If you receive intermediate certificates, use a text editor and paste your certificate on top and then the intermediate certificates
|
||||||
below it. Save the file and place it onto this machine at %s. Then run "service nginx restart".""" % ssl_certificate)
|
below it. Save the file and place it onto this machine at %s. Then run "service nginx restart".""" % ssl_certificate)
|
||||||
|
|
||||||
elif cert_status == "OK":
|
|
||||||
env['out'].print_ok("SSL certificate is signed & valid.")
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
env['out'].print_error("The SSL certificate has a problem:")
|
env['out'].print_error("The SSL certificate has a problem: " + cert_status)
|
||||||
|
if cert_status_details:
|
||||||
env['out'].print_line("")
|
env['out'].print_line("")
|
||||||
env['out'].print_line(cert_status)
|
env['out'].print_line(cert_status_details)
|
||||||
env['out'].print_line("")
|
env['out'].print_line("")
|
||||||
|
|
||||||
def check_certificate(domain, ssl_certificate, ssl_private_key):
|
def check_certificate(domain, ssl_certificate, ssl_private_key):
|
||||||
@ -444,8 +448,8 @@ def check_certificate(domain, ssl_certificate, ssl_private_key):
|
|||||||
|
|
||||||
wildcard_domain = re.sub("^[^\.]+", "*", domain)
|
wildcard_domain = re.sub("^[^\.]+", "*", domain)
|
||||||
if domain is not None and domain not in certificate_names and wildcard_domain not in certificate_names:
|
if domain is not None and domain not in certificate_names and wildcard_domain not in certificate_names:
|
||||||
return "This certificate is for the wrong domain names. It is for %s." % \
|
return ("The certificate is for the wrong domain name. It is for %s."
|
||||||
", ".join(sorted(certificate_names))
|
% ", ".join(sorted(certificate_names)), None)
|
||||||
|
|
||||||
# Second, check that the certificate matches the private key. Get the modulus of the
|
# Second, check that the certificate matches the private key. Get the modulus of the
|
||||||
# private key and of the public key in the certificate. They should match. The output
|
# private key and of the public key in the certificate. They should match. The output
|
||||||
@ -461,7 +465,7 @@ def check_certificate(domain, ssl_certificate, ssl_private_key):
|
|||||||
"-in", ssl_certificate,
|
"-in", ssl_certificate,
|
||||||
"-noout", "-modulus"])
|
"-noout", "-modulus"])
|
||||||
if private_key_modulus != cert_key_modulus:
|
if private_key_modulus != cert_key_modulus:
|
||||||
return "The certificate installed at %s does not correspond to the private key at %s." % (ssl_certificate, ssl_private_key)
|
return ("The certificate installed at %s does not correspond to the private key at %s." % (ssl_certificate, ssl_private_key), None)
|
||||||
|
|
||||||
# Next validate that the certificate is valid. This checks whether the certificate
|
# Next validate that the certificate is valid. This checks whether the certificate
|
||||||
# is self-signed, that the chain of trust makes sense, that it is signed by a CA
|
# is self-signed, that the chain of trust makes sense, that it is signed by a CA
|
||||||
@ -475,7 +479,7 @@ def check_certificate(domain, ssl_certificate, ssl_private_key):
|
|||||||
cert = open(ssl_certificate).read()
|
cert = open(ssl_certificate).read()
|
||||||
m = re.match(r'(-*BEGIN CERTIFICATE-*.*?-*END CERTIFICATE-*)(.*)', cert, re.S)
|
m = re.match(r'(-*BEGIN CERTIFICATE-*.*?-*END CERTIFICATE-*)(.*)', cert, re.S)
|
||||||
if m == None:
|
if m == None:
|
||||||
return "The certificate file is an invalid PEM certificate."
|
return ("The certificate file is an invalid PEM certificate.", None)
|
||||||
mycert, chaincerts = m.groups()
|
mycert, chaincerts = m.groups()
|
||||||
|
|
||||||
# This command returns a non-zero exit status in most cases, so trap errors.
|
# This command returns a non-zero exit status in most cases, so trap errors.
|
||||||
@ -491,10 +495,10 @@ def check_certificate(domain, ssl_certificate, ssl_private_key):
|
|||||||
|
|
||||||
if "self signed" in verifyoutput:
|
if "self signed" in verifyoutput:
|
||||||
# Certificate is self-signed.
|
# Certificate is self-signed.
|
||||||
return "SELF-SIGNED"
|
return ("SELF-SIGNED", None)
|
||||||
elif retcode != 0:
|
elif retcode != 0:
|
||||||
# There is some unknown problem. Return the `openssl verify` raw output.
|
# There is some unknown problem. Return the `openssl verify` raw output.
|
||||||
return verifyoutput.strip()
|
return ("There is a problem with the SSL certificate.", verifyoutput.strip())
|
||||||
else:
|
else:
|
||||||
# `openssl verify` returned a zero exit status so the cert is currently
|
# `openssl verify` returned a zero exit status so the cert is currently
|
||||||
# good.
|
# good.
|
||||||
@ -502,11 +506,12 @@ def check_certificate(domain, ssl_certificate, ssl_private_key):
|
|||||||
# But is it expiring soon?
|
# But is it expiring soon?
|
||||||
now = datetime.datetime.now(dateutil.tz.tzlocal())
|
now = datetime.datetime.now(dateutil.tz.tzlocal())
|
||||||
ndays = (cert_expiration_date-now).days
|
ndays = (cert_expiration_date-now).days
|
||||||
|
expiry_info = "The certificate expires in %d days on %s." % (ndays, cert_expiration_date.strftime("%x"))
|
||||||
if ndays <= 31:
|
if ndays <= 31:
|
||||||
return "This certificate expires in %d days on %s." % (ndays, cert_expiration_date.strftime("%x"))
|
return ("The certificate is expiring soon: " + expiry_info, None)
|
||||||
|
|
||||||
# Return the special OK code.
|
# Return the special OK code.
|
||||||
return "OK"
|
return ("OK", expiry_info)
|
||||||
|
|
||||||
_apt_updates = None
|
_apt_updates = None
|
||||||
def list_apt_updates(apt_update=True):
|
def list_apt_updates(apt_update=True):
|
||||||
@ -592,7 +597,7 @@ if __name__ == "__main__":
|
|||||||
ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env)
|
ssl_key, ssl_certificate, ssl_csr_path = get_domain_ssl_files(domain, env)
|
||||||
if not os.path.exists(ssl_certificate):
|
if not os.path.exists(ssl_certificate):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
cert_status = check_certificate(domain, ssl_certificate, ssl_key)
|
cert_status, cert_status_details = check_certificate(domain, ssl_certificate, ssl_key)
|
||||||
if cert_status != "OK":
|
if cert_status != "OK":
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
@ -146,7 +146,7 @@ def get_domain_ssl_files(domain, env):
|
|||||||
# the user has uploaded a different private key for this domain.
|
# the user has uploaded a different private key for this domain.
|
||||||
if not ssl_key_is_alt:
|
if not ssl_key_is_alt:
|
||||||
from status_checks import check_certificate
|
from status_checks import check_certificate
|
||||||
if check_certificate(domain, ssl_certificate_primary, None) == "OK":
|
if check_certificate(domain, ssl_certificate_primary, None)[0] == "OK":
|
||||||
ssl_certificate = ssl_certificate_primary
|
ssl_certificate = ssl_certificate_primary
|
||||||
|
|
||||||
# Where would the CSR go? As with the SSL cert itself, the CSR must be
|
# Where would the CSR go? As with the SSL cert itself, the CSR must be
|
||||||
|
Loading…
Reference in New Issue
Block a user