Files
@ c01402cc810c
Branch filter:
Location: C3L-NOC/tls-expiry-tracker/backend/tls_utils.py
c01402cc810c
4.1 KiB
text/x-python
feat: web is now https, which is a special case of tls
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | #!/usr/bin/env python3
from rich.console import Console
import datetime
EXPIRED = 10
REVOKED = 23
SELF_SIGNED = 18
ROOT_NOT_TRUSTED = 19
class TLSDetails:
domain_name = None
expiry_timestamp_utc = None
error_message = None
connection_error = False
def __init__(self, domain_name : str = None, expiry_timestamp_utc : int = None, error_message : str = None, connection_error : bool = False):
self.domain_name = domain_name
self.expiry_timestamp_utc = expiry_timestamp_utc
self.error_message = error_message
self.connection_error = connection_error
# Green - Valid
# Orange - Non-TLS error
# Red - TLS error
def print(self, console: Console):
if self.connection_error:
console.log("[bold underline]" + self.domain_name, self.error_message, style="orange")
elif self.error_message != None:
console.log("[bold underline]" + self.domain_name, self.error_message, style="red")
else:
msg, future = self.relative_time_comparison()
if not future:
console.log("[bold underline]" + self.domain_name, "expired", msg + ".", style="red")
else:
console.log("[bold underline]" + self.domain_name, "expires", msg + ".", style="green")
def is_valid(self) -> bool:
if self.connection_error:
return None
return (self.error_message is None) and (not self.is_expired())
def is_expired(self) -> bool:
if self.expiry_timestamp_utc is None:
return True
now_timestamp = datetime.datetime.now(datetime.UTC).timestamp()
# notAfter, so it includes the second itself
return now_timestamp >= self.expiry_timestamp_utc
# Returns a human-readable relative string, and if the date is future (true) or past (false)
def relative_time_comparison(self, now = datetime.datetime.now(datetime.UTC).timestamp()) -> tuple[str, bool]:
if self.expiry_timestamp_utc is None:
return ""
diff = round(self.expiry_timestamp_utc) - round(now)
future = diff > 0
seconds_diff = int(abs(diff))
minutes_diff = seconds_diff // 60
hours_diff = minutes_diff // 60
days_diff = hours_diff // 24
months_diff = days_diff // 30
msg = ""
if months_diff > 0:
days_diff = days_diff % 30
msg += str(months_diff) + " month" + ("s" if months_diff > 1 else "")
if future and months_diff < 3 and days_diff > 0:
msg += " and " + str(days_diff) + " day" + ("s" if days_diff > 1 else "")
elif days_diff > 0:
msg += str(days_diff) + " day" + ("s" if days_diff > 1 else "")
elif hours_diff > 0:
msg += str(hours_diff) + " hour" + ("s" if hours_diff > 1 else "")
elif minutes_diff > 0:
msg += str(minutes_diff) + " minute" + ("s" if minutes_diff > 1 else "")
elif seconds_diff > 0:
msg += str(seconds_diff) + " second" + ("s" if seconds_diff > 1 else "")
else:
msg = "now"
if future:
if seconds_diff > 0:
msg = "in " + msg
else:
if seconds_diff > 0:
msg = msg + " ago"
return (msg, future)
def get_cert_expiry_timestamp(cert) -> int:
notAfter = cert['notAfter']
notAfter_date = datetime.datetime.strptime(notAfter, '%b %d %H:%M:%S %Y %Z').astimezone(datetime.UTC)
return notAfter_date.timestamp()
# Test expiry checking (timestamps)
if __name__ == "__main__":
console = Console()
test = TLSDetails(domain_name="now.example.org", expiry_timestamp_utc=datetime.datetime.now(datetime.UTC).timestamp())
console.log("Now: ", test.relative_time_comparison())
test = TLSDetails(domain_name="past.example.org", expiry_timestamp_utc=datetime.datetime.now(datetime.UTC).timestamp() - 1)
console.log("Past: ", test.relative_time_comparison())
test = TLSDetails(domain_name="future.example.org", expiry_timestamp_utc=datetime.datetime.now(datetime.UTC).timestamp() + 1)
console.log("Future: ", test.relative_time_comparison())
|