From b60cba137cb7611bac7005fe483cc8d760343e1c Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Sat, 20 Apr 2024 16:08:54 -0700 Subject: [PATCH 1/6] Add support for WIZNET5K ssl --- adafruit_connection_manager.py | 24 ++++++++++++++++++++++-- tests/conftest.py | 14 ++++++++++++++ tests/fake_ssl_context_test.py | 5 ++++- tests/get_radio_test.py | 7 +++++-- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/adafruit_connection_manager.py b/adafruit_connection_manager.py index cc70f3f..9f564e3 100644 --- a/adafruit_connection_manager.py +++ b/adafruit_connection_manager.py @@ -128,8 +128,28 @@ def get_radio_socketpool(radio): elif class_name == "WIZNET5K": import adafruit_wiznet5k.adafruit_wiznet5k_socket as pool # pylint: disable=import-outside-toplevel - # Note: SSL/TLS connections are not supported by the Wiznet5k library at this time - ssl_context = create_fake_ssl_context(pool, radio) + # Note: At this time, SSL/TLS connections are not supported by older + # versions of the Wiznet5k library or on boards withouut the ssl module + # see https://docs.circuitpython.org/en/latest/shared-bindings/support_matrix.html + ssl_context = None + try_ssl = False + cp_version = sys.implementation[1] + if pool.SOCK_STREAM == 1 and cp_version[0] >= 9: + if cp_version[0] > 9: + try_ssl = True + elif cp_version[0] == 9 and cp_version[1] >= 1: + try_ssl = True + + if try_ssl: + try: + import ssl # pylint: disable=import-outside-toplevel + + ssl_context = ssl.create_default_context() + except ImportError: + """SSL not on board default to fake_ssl_context""" + + if ssl_context is None: + ssl_context = create_fake_ssl_context(pool, radio) else: raise AttributeError(f"Unsupported radio class: {class_name}") diff --git a/tests/conftest.py b/tests/conftest.py index 2d9bb0a..e1b2426 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,6 +7,7 @@ import sys import mocket +import pytest # pylint: disable=unused-argument @@ -27,5 +28,18 @@ def set_interface(iface): wiznet5k_module = type(sys)("adafruit_wiznet5k") wiznet5k_socket_module = type(sys)("adafruit_wiznet5k_socket") wiznet5k_socket_module.set_interface = set_interface +wiznet5k_socket_module.SOCK_STREAM = 0x21 sys.modules["adafruit_wiznet5k"] = wiznet5k_module sys.modules["adafruit_wiznet5k.adafruit_wiznet5k_socket"] = wiznet5k_socket_module + + +@pytest.fixture(autouse=True) +def reset_connection_manager(monkeypatch): + monkeypatch.setattr( + "adafruit_connection_manager._global_socketpool", + {}, + ) + monkeypatch.setattr( + "adafruit_connection_manager._global_ssl_contexts", + {}, + ) diff --git a/tests/fake_ssl_context_test.py b/tests/fake_ssl_context_test.py index fc566ea..80887d8 100644 --- a/tests/fake_ssl_context_test.py +++ b/tests/fake_ssl_context_test.py @@ -4,6 +4,8 @@ """ FakeSLLSocket Tests """ +from unittest import mock + import mocket import pytest @@ -34,7 +36,8 @@ def test_connect_https_not_supported(): mock_pool.socket.return_value = mock_socket_1 radio = mocket.MockRadio.WIZNET5K() - ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio) + with mock.patch("sys.implementation", return_value=[9, 0, 0]): + ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio) connection_manager = adafruit_connection_manager.ConnectionManager(mock_pool) # verify a HTTPS call for a board without built in WiFi and SSL support errors diff --git a/tests/get_radio_test.py b/tests/get_radio_test.py index ea80f7e..2925f56 100644 --- a/tests/get_radio_test.py +++ b/tests/get_radio_test.py @@ -5,6 +5,7 @@ """ Get socketpool and ssl_context Tests """ import ssl +from unittest import mock import mocket import pytest @@ -26,7 +27,8 @@ def test_get_radio_socketpool_esp32spi(): def test_get_radio_socketpool_wiznet5k(): radio = mocket.MockRadio.WIZNET5K() - socket_pool = adafruit_connection_manager.get_radio_socketpool(radio) + with mock.patch("sys.implementation", return_value=[9, 0, 0]): + socket_pool = adafruit_connection_manager.get_radio_socketpool(radio) assert socket_pool.__name__ == "adafruit_wiznet5k_socket" @@ -58,7 +60,8 @@ def test_get_radio_ssl_context_esp32spi(): def test_get_radio_ssl_context_wiznet5k(): radio = mocket.MockRadio.WIZNET5K() - ssl_contexts = adafruit_connection_manager.get_radio_ssl_context(radio) + with mock.patch("sys.implementation", return_value=[9, 0, 0]): + ssl_contexts = adafruit_connection_manager.get_radio_ssl_context(radio) assert isinstance(ssl_contexts, adafruit_connection_manager._FakeSSLContext) From 1a3b276be3ba24192025d4891933e7b03a5bdde4 Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Wed, 24 Apr 2024 16:52:44 -0700 Subject: [PATCH 2/6] Fix issue with pool interface --- adafruit_connection_manager.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/adafruit_connection_manager.py b/adafruit_connection_manager.py index 9f564e3..75fdc2c 100644 --- a/adafruit_connection_manager.py +++ b/adafruit_connection_manager.py @@ -29,6 +29,8 @@ import errno import sys +WIZNET5K_SSL_SUPPORT_VERSION = (9, 1) + # typing @@ -132,21 +134,15 @@ def get_radio_socketpool(radio): # versions of the Wiznet5k library or on boards withouut the ssl module # see https://docs.circuitpython.org/en/latest/shared-bindings/support_matrix.html ssl_context = None - try_ssl = False cp_version = sys.implementation[1] - if pool.SOCK_STREAM == 1 and cp_version[0] >= 9: - if cp_version[0] > 9: - try_ssl = True - elif cp_version[0] == 9 and cp_version[1] >= 1: - try_ssl = True - - if try_ssl: - try: - import ssl # pylint: disable=import-outside-toplevel - - ssl_context = ssl.create_default_context() - except ImportError: - """SSL not on board default to fake_ssl_context""" + if pool.SOCK_STREAM == 1 and cp_version >= WIZNET5K_SSL_SUPPORT_VERSION: + try: + import ssl # pylint: disable=import-outside-toplevel + + ssl_context = ssl.create_default_context() + pool.set_interface(radio) + except ImportError: + """SSL not on board default to fake_ssl_context""" if ssl_context is None: ssl_context = create_fake_ssl_context(pool, radio) From 8e789a69667b062456e0bf1544c3ea3ec6c98bab Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Wed, 24 Apr 2024 21:41:11 -0700 Subject: [PATCH 3/6] Add tests --- tests/conftest.py | 13 +++++++++++++ tests/ssl_context_test.py | 19 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 7947b1c..08d3914 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -49,6 +49,19 @@ def adafruit_wiznet5k_socket_module(): del sys.modules["adafruit_wiznet5k.adafruit_wiznet5k_socket"] +@pytest.fixture +def adafruit_wiznet5k_with_ssl_socket_module(): + wiznet5k_module = type(sys)("adafruit_wiznet5k") + wiznet5k_socket_module = type(sys)("adafruit_wiznet5k_socket") + wiznet5k_socket_module.set_interface = set_interface + wiznet5k_socket_module.SOCK_STREAM = 1 + sys.modules["adafruit_wiznet5k"] = wiznet5k_module + sys.modules["adafruit_wiznet5k.adafruit_wiznet5k_socket"] = wiznet5k_socket_module + yield + del sys.modules["adafruit_wiznet5k"] + del sys.modules["adafruit_wiznet5k.adafruit_wiznet5k_socket"] + + @pytest.fixture(autouse=True) def reset_connection_manager(monkeypatch): monkeypatch.setattr( diff --git a/tests/ssl_context_test.py b/tests/ssl_context_test.py index 68ff98b..112ef8a 100644 --- a/tests/ssl_context_test.py +++ b/tests/ssl_context_test.py @@ -11,6 +11,7 @@ import pytest import adafruit_connection_manager +from adafruit_connection_manager import WIZNET5K_SSL_SUPPORT_VERSION def test_connect_esp32spi_https( # pylint: disable=unused-argument @@ -51,7 +52,11 @@ def test_connect_wiznet5k_https_not_supported( # pylint: disable=unused-argumen ): mock_pool = mocket.MocketPool() radio = mocket.MockRadio.WIZNET5K() - with mock.patch("sys.implementation", return_value=[9, 0, 0]): + old_version = (WIZNET5K_SSL_SUPPORT_VERSION[0] - 1, 0, 0) + with mock.patch( + "sys.implementation", + (None, old_version) + ): ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio) connection_manager = adafruit_connection_manager.ConnectionManager(mock_pool) @@ -61,3 +66,15 @@ def test_connect_wiznet5k_https_not_supported( # pylint: disable=unused-argumen mocket.MOCK_HOST_1, 443, "https:", ssl_context=ssl_context ) assert "This radio does not support TLS/HTTPS" in str(context) + + +def test_connect_wiznet5k_https_supported( # pylint: disable=unused-argument + adafruit_wiznet5k_with_ssl_socket_module, +): + radio = mocket.MockRadio.WIZNET5K() + with mock.patch( + "sys.implementation", + (None, WIZNET5K_SSL_SUPPORT_VERSION) + ): + ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio) + assert isinstance(ssl_context, ssl.SSLContext) From 62b564356bfe9fbf69a751aca5852fd4e29def80 Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Wed, 24 Apr 2024 21:47:06 -0700 Subject: [PATCH 4/6] lint fixes --- tests/ssl_context_test.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/ssl_context_test.py b/tests/ssl_context_test.py index 112ef8a..de6d4f1 100644 --- a/tests/ssl_context_test.py +++ b/tests/ssl_context_test.py @@ -53,10 +53,7 @@ def test_connect_wiznet5k_https_not_supported( # pylint: disable=unused-argumen mock_pool = mocket.MocketPool() radio = mocket.MockRadio.WIZNET5K() old_version = (WIZNET5K_SSL_SUPPORT_VERSION[0] - 1, 0, 0) - with mock.patch( - "sys.implementation", - (None, old_version) - ): + with mock.patch("sys.implementation", (None, old_version)): ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio) connection_manager = adafruit_connection_manager.ConnectionManager(mock_pool) @@ -72,9 +69,6 @@ def test_connect_wiznet5k_https_supported( # pylint: disable=unused-argument adafruit_wiznet5k_with_ssl_socket_module, ): radio = mocket.MockRadio.WIZNET5K() - with mock.patch( - "sys.implementation", - (None, WIZNET5K_SSL_SUPPORT_VERSION) - ): + with mock.patch("sys.implementation", (None, WIZNET5K_SSL_SUPPORT_VERSION)): ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio) assert isinstance(ssl_context, ssl.SSLContext) From a8f7e9a21d008b031d0441de127fd270d7fd9bb3 Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Thu, 25 Apr 2024 12:02:26 -0700 Subject: [PATCH 5/6] Update adafruit_connection_manager.py Co-authored-by: Dan Halbert --- adafruit_connection_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_connection_manager.py b/adafruit_connection_manager.py index 75fdc2c..61abf50 100644 --- a/adafruit_connection_manager.py +++ b/adafruit_connection_manager.py @@ -142,7 +142,7 @@ def get_radio_socketpool(radio): ssl_context = ssl.create_default_context() pool.set_interface(radio) except ImportError: - """SSL not on board default to fake_ssl_context""" + # if SSL not on board, default to fake_ssl_context if ssl_context is None: ssl_context = create_fake_ssl_context(pool, radio) From 7ffe4bda4f347aeae23b3af90127ba5bbd1ae02b Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Thu, 25 Apr 2024 12:06:30 -0700 Subject: [PATCH 6/6] Fix except block --- adafruit_connection_manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/adafruit_connection_manager.py b/adafruit_connection_manager.py index 61abf50..7c4d896 100644 --- a/adafruit_connection_manager.py +++ b/adafruit_connection_manager.py @@ -143,6 +143,7 @@ def get_radio_socketpool(radio): pool.set_interface(radio) except ImportError: # if SSL not on board, default to fake_ssl_context + pass if ssl_context is None: ssl_context = create_fake_ssl_context(pool, radio)