From 7174c6df0c93dbcdd8448f305ce0f5290452deb7 Mon Sep 17 00:00:00 2001 From: ohmdelta <64962148+ohmdelta@users.noreply.github.com> Date: Sat, 19 Jul 2025 21:55:17 +0100 Subject: [PATCH] port fixes from ha bambulab for ftps --- bambulabs_api/bambu.cert | 21 +++++++++++++++++++++ bambulabs_api/ftp_client.py | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 bambulabs_api/bambu.cert diff --git a/bambulabs_api/bambu.cert b/bambulabs_api/bambu.cert new file mode 100644 index 0000000..0bee464 --- /dev/null +++ b/bambulabs_api/bambu.cert @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDZTCCAk2gAwIBAgIUV1FckwXElyek1onFnQ9kL7Bk4N8wDQYJKoZIhvcNAQEL +BQAwQjELMAkGA1UEBhMCQ04xIjAgBgNVBAoMGUJCTCBUZWNobm9sb2dpZXMgQ28u +LCBMdGQxDzANBgNVBAMMBkJCTCBDQTAeFw0yMjA0MDQwMzQyMTFaFw0zMjA0MDEw +MzQyMTFaMEIxCzAJBgNVBAYTAkNOMSIwIAYDVQQKDBlCQkwgVGVjaG5vbG9naWVz +IENvLiwgTHRkMQ8wDQYDVQQDDAZCQkwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDL3pnDdxGOk5Z6vugiT4dpM0ju+3Xatxz09UY7mbj4tkIdby4H +oeEdiYSZjc5LJngJuCHwtEbBJt1BriRdSVrF6M9D2UaBDyamEo0dxwSaVxZiDVWC +eeCPdELpFZdEhSNTaT4O7zgvcnFsfHMa/0vMAkvE7i0qp3mjEzYLfz60axcDoJLk +p7n6xKXI+cJbA4IlToFjpSldPmC+ynOo7YAOsXt7AYKY6Glz0BwUVzSJxU+/+VFy +/QrmYGNwlrQtdREHeRi0SNK32x1+bOndfJP0sojuIrDjKsdCLye5CSZIvqnbowwW +1jRwZgTBR29Zp2nzCoxJYcU9TSQp/4KZuWNVAgMBAAGjUzBRMB0GA1UdDgQWBBSP +NEJo3GdOj8QinsV8SeWr3US+HjAfBgNVHSMEGDAWgBSPNEJo3GdOj8QinsV8SeWr +3US+HjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQABlBIT5ZeG +fgcK1LOh1CN9sTzxMCLbtTPFF1NGGA13mApu6j1h5YELbSKcUqfXzMnVeAb06Htu +3CoCoe+wj7LONTFO++vBm2/if6Jt/DUw1CAEcNyqeh6ES0NX8LJRVSe0qdTxPJuA +BdOoo96iX89rRPoxeed1cpq5hZwbeka3+CJGV76itWp35Up5rmmUqrlyQOr/Wax6 +itosIzG0MfhgUzU51A2P/hSnD3NDMXv+wUY/AvqgIL7u7fbDKnku1GzEKIkfH8hm +Rs6d8SCU89xyrwzQ0PR853irHas3WrHVqab3P+qNwR0YirL0Qk7Xt/q3O1griNg2 +Blbjg3obpHo9 +-----END CERTIFICATE----- \ No newline at end of file diff --git a/bambulabs_api/ftp_client.py b/bambulabs_api/ftp_client.py index 7daa8a7..04c43da 100644 --- a/bambulabs_api/ftp_client.py +++ b/bambulabs_api/ftp_client.py @@ -2,7 +2,10 @@ import ftplib +import functools from io import BytesIO +import os +from socket import socket import ssl from PIL import Image @@ -31,6 +34,16 @@ def sock(self, value): # type: ignore value = self.context.wrap_socket(value) self._sock = value + def ntransfercmd(self, cmd: str, rest: int | str | None = None) -> tuple[socket, int | None]: + conn, size = ftplib.FTP.ntransfercmd(self, cmd, rest) + + if self._prot_p: # type: ignore + assert self.sock is not None + conn = self.context.wrap_socket( + conn, server_hostname=self.host, session=self.sock.session + ) # this is the fix + return conn, size + def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None): self.voidcmd('TYPE I') conn = self.transfercmd(cmd, rest) @@ -51,13 +64,31 @@ def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None): return self.voidresp() +@functools.lru_cache(maxsize=1) +def create_local_ssl_context(): + """ + This context validates the certificate for TLS connections to local printers. + """ + script_path = os.path.abspath(__file__) + directory_path = os.path.dirname(script_path) + certfile = directory_path + "/bambu.cert" + context = ssl.create_default_context(cafile=certfile) + # Ignore "CA cert does not include key usage extension" error since python 3.13 + # See note in https://docs.python.org/3/library/ssl.html#ssl.create_default_context + context.verify_flags &= ~ssl.VERIFY_X509_STRICT + # Workaround because some users get this error despite SNI: "certificate verify failed: IP address mismatch" + context.check_hostname = False + return context + + class PrinterFTPClient: def __init__(self, server_ip: str, access_code: str, user: str = 'bblp', port: int = 990) -> None: - self.ftps = ImplicitFTP_TLS() + self._context = create_local_ssl_context() + self.ftps = ImplicitFTP_TLS(self._context) self.server_ip = server_ip self.port = port @@ -73,7 +104,7 @@ def connect_and_run(func): func (function): the function to be decorated """ # noqa - def wrapper(self, *args, **kwargs) -> Any: + def wrapper(self: 'PrinterFTPClient', *args, **kwargs) -> Any: logging.info("Connecting to FTP server...") self.ftps.connect(host=self.server_ip, port=self.port) self.ftps.login(self.user, self.access_code)