Files @ d969304ee9cb
Branch filter:

Location: C3L-NOC/tls-expiry-tracker/backend/mail.py - annotation

x
style: remove empty line spaces
#!/usr/bin/env python3
import ssl
import smtplib
import imaplib
from rich.console import Console
from cryptography import x509
import tls_utils
from tls_utils import TLSDetails
from abc import ABC, abstractmethod

class MailHandler(ABC):
    def __init__(self, host: str, port: int, context: ssl.SSLContext):
        self.host = host
        self.port = port
        self.context = context

    def connect(self, verification: bool) -> int:
        connection = self.protocol_init(self.host, self.port)
        if verification:
            connection.starttls(**self.protocol_starttls_args())
        else:
            connection.starttls()
        cert = connection.sock.getpeercert()
        self.protocol_close(connection)
        return tls_utils.get_validity_days(cert)[1]

    @abstractmethod
    def protocol_init(self, host, port):
        raise NotImplementedError()
    @abstractmethod
    def protocol_close(self, connection):
        raise NotImplementedError()
    @abstractmethod
    def protocol_starttls_args(self):
        raise NotImplementedError()

    @staticmethod
    def create_handler(protocol: str):
        if protocol == "smtp":
            return SMTPHandler
        elif protocol == "imap":
            return IMAPHandler
        else:
            raise ValueError("Invalid protocol")

class IMAPHandler(MailHandler):
    def protocol_init(self, host, port):
        return imaplib.IMAP4(host, port)
    def protocol_close(self, connection):
        connection.logout()
    def protocol_starttls_args(self):
        return {"ssl_context": self.context}

class SMTPHandler(MailHandler):
    def protocol_init(self, host, port):
        return smtplib.SMTP(host, port)
    def protocol_close(self, connection):
        connection.quit()
    def protocol_starttls_args(self):
        return {"context": self.context}

class MailVerificator:
    def __init__(self, context: ssl.SSLContext):
        self.context = context

    def connect(self, domain: str, port: int, protocol: str) -> TLSDetails:
        mail = MailHandler.create_handler(protocol)(domain, port, self.context)
        try:
            expiry = mail.connect(True)
            return TLSDetails(domain_name=domain, expires_in_days=expiry)
        except ssl.SSLCertVerificationError as e:
            if (e.verify_code == tls_utils.EXPIRED_VERIFY_CODE):
                expiry = mail.connect(False)
                return TLSDetails(domain_name=domain, expires_in_days=expiry)
            else:
                error = "failed verification:", e.verify_message + "."
                return TLSDetails(domain_name=domain, error_message=error)