diff --git a/backend/generic_handler.py b/backend/generic_handler.py new file mode 100644 index 0000000000000000000000000000000000000000..e27301ee8b701777c44815ea338198a85ae9a011 --- /dev/null +++ b/backend/generic_handler.py @@ -0,0 +1,50 @@ +from abc import ABC, abstractmethod +import ssl +from tls_utils import TLSDetails, EXPIRED, REVOKED, SELF_SIGNED, ROOT_NOT_TRUSTED + +class GenericHandler(ABC): + def __init__(self, host: str, port: int, context: ssl.SSLContext): + self.host = host + self.port = port + self.context = context + + @abstractmethod + def connect(self, verification: bool) -> int: + raise NotImplementedError() + + @staticmethod + def create_handler(protocol: str): + import web, mail + if protocol == "smtp": + return mail.SMTPHandler + elif protocol == "imap": + return mail.IMAPHandler + elif protocol == "ssl" or protocol == "tls" or protocol == "https": + return web.SSLHandler + else: + raise ValueError("Invalid protocol") + +class Verificator: + def __init__(self, context: ssl.SSLContext): + self.context = context + def connect(self, domain: str, port: int, protocol: str) -> TLSDetails: + handler = GenericHandler.create_handler(protocol)(domain, port, self.context) + try: + expiry = handler.connect(True) + return TLSDetails(domain_name=domain, expires_in_days=expiry) + except ssl.SSLCertVerificationError as e: + if e.verify_code == EXPIRED: + expiry = handler.connect(False) + return TLSDetails(domain_name=domain, expires_in_days=expiry) + elif e.verify_code == REVOKED: + return TLSDetails(domain_name=domain, error_message="was revoked.") + elif e.verify_code == SELF_SIGNED: + return TLSDetails(domain_name=domain, error_message="is self-signed.") + elif e.verify_code == ROOT_NOT_TRUSTED: + return TLSDetails(domain_name=domain, error_message="invalid: root not trusted.") + else: + return TLSDetails(domain_name=domain, error_message="failed verification: " + e.verify_message + ".") + except ssl.SSLError as e: + return TLSDetails(domain_name=domain, error_message="could not establish a secure connection: " + e.reason + ".") + except Exception as e: + return TLSDetails(domain_name=domain, error_message="could not connect: " + str(e) + ".") \ No newline at end of file