Преглед изворни кода

fix(tls): declare TLS 1.2 as the minimum for printer FTPS and MQTT

ssl.create_default_context() leaves minimum_version at MINIMUM_SUPPORTED,
so the floor came from the OpenSSL build rather than from Bambuddy. On
identical OpenSSL 3.5.6, python:3.13-slim-trixie reports TLSv1_2 while a
bare-metal venv reports MINIMUM_SUPPORTED -- Docker installs were floored
at 1.2, bare-metal and appliance installs were not.

Set minimum_version explicitly in ImplicitFTP_TLS and the MQTT client. On
the P2S/X2D profiles that also cap maximum_version this becomes an exact
TLS 1.2 pin. Probed against an X1C and an H2D on :990 and :8883: both
complete only on TLS 1.2 and reject 1.0, 1.1 and 1.3; live FTPS login
through the new path succeeds on both.

Also correct a stale comment in ftp_profiles.py -- X1C and H2D refuse
TLS 1.3, so cap_tls_v1_2 is a no-op there, contrary to what it claimed.
maziggy пре 1 месец
родитељ
комит
77f8a3a3ff

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
CHANGELOG.md


+ 11 - 0
backend/app/services/bambu_ftp.py

@@ -64,7 +64,18 @@ class ImplicitFTP_TLS(FTP_TLS):
         self.ssl_context = ssl.create_default_context()
         self.ssl_context.check_hostname = False
         self.ssl_context.verify_mode = ssl.CERT_NONE
+        # ``create_default_context()`` does NOT guarantee a protocol floor: it
+        # leaves ``minimum_version`` at ``MINIMUM_SUPPORTED``, and what that
+        # resolves to is a property of the OpenSSL build, not of this code.
+        # Measured on identical OpenSSL 3.5.6: python:3.13-slim-trixie (our
+        # Docker base) reports TLSv1_2, a bare-metal venv reports
+        # MINIMUM_SUPPORTED. Docker users have therefore always been floored at
+        # 1.2 — every Bambu model is reachable under that floor — while
+        # bare-metal and appliance installs could silently negotiate TLS 1.0.
+        # State the floor rather than inheriting it.
+        self.ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
         if cap_tls_v1_2:
+            # With the floor above this pins the connection to exactly TLS 1.2.
             self.ssl_context.maximum_version = ssl.TLSVersion.TLSv1_2
 
     def connect(self, host="", port=990, timeout=-999, source_address=None):

+ 6 - 0
backend/app/services/bambu_mqtt.py

@@ -3596,6 +3596,12 @@ class BambuMQTTClient:
         ssl_context = ssl.create_default_context()
         ssl_context.check_hostname = False
         ssl_context.verify_mode = ssl.CERT_NONE
+        # Same reasoning as ImplicitFTP_TLS in bambu_ftp.py: create_default_context()
+        # inherits its protocol floor from the OpenSSL build instead of declaring one.
+        # Every Bambu broker measured (X1C, H2D on :8883) speaks TLS 1.2 and refuses
+        # 1.0/1.1/1.3, so this floor is a no-op on the wire and closes the gap on
+        # bare-metal installs whose build allows TLS 1.0.
+        ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
         self._client.tls_set_context(ssl_context)
 
         # Backoff reconnects to avoid tight reconnect loops on unstable brokers.

+ 13 - 9
backend/app/services/ftp_profiles.py

@@ -34,10 +34,8 @@ class FTPProfile:
 
     # Pin the SSL context's ``maximum_version`` to TLS 1.2.
     #
-    # Python 3.13's default ``ssl.create_default_context()`` negotiates
-    # TLS 1.3 when both peers support it. The Bambuddy Docker image is
-    # ``python:3.13-slim-trixie``, so every Docker user gets 1.3 by
-    # default. Some Bambu printer firmwares (P2S 01.02.00.00 confirmed
+    # ``ssl.create_default_context()`` negotiates TLS 1.3 when both peers
+    # support it. Some Bambu printer firmwares (P2S 01.02.00.00 confirmed
     # by @iitazz, #1401) implement session reuse on the FTPS data
     # channel against an old vsFTPd build that doesn't tolerate TLS
     # 1.3's asynchronous session-ticket model: the data channel gets
@@ -47,12 +45,18 @@ class FTPProfile:
     # the printer). Capping to TLS 1.2 makes session resumption
     # synchronous and the upload completes normally.
     #
+    # Note this cap only bites on models that *offer* 1.3 in the first
+    # place. Probed directly on :990, an X1C and an H2D both refuse
+    # TLS 1.0, 1.1 and 1.3 with a handshake_failure alert and complete
+    # only on 1.2 — so for those models the cap is a no-op and the
+    # negotiated version was never 1.3. The P2S evidently does offer
+    # 1.3, which is why it alone surfaced the session-reuse bug.
+    # (P1S untested; no claim made either way.)
+    #
     # **Defaults to False** — only applied to printer models where a
-    # reporter has confirmed the symptom. Existing P1S / X1C / H2D
-    # installs that work fine today stay on the negotiated TLS 1.3.
-    # This is deliberately conservative; flipping a printer to the
-    # capped path is a config edit when a new model surfaces the
-    # same bug.
+    # reporter has confirmed the symptom. This is deliberately
+    # conservative; flipping a printer to the capped path is a config
+    # edit when a new model surfaces the same bug.
     cap_tls_v1_2: bool = False
 
 

Неке датотеке нису приказане због велике количине промена