Examples¶
Below are a few examples, there may be more in the examples folder of the library
Helper example¶
This example shows you how to use the adafruit_connection_manager
helpers to help
simplify code when writing it for multiple different boards
1# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries
2#
3# SPDX-License-Identifier: Unlicense
4
5import os
6
7import adafruit_requests
8import wifi
9
10import adafruit_connection_manager
11
12TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html"
13
14wifi_ssid = os.getenv("CIRCUITPY_WIFI_SSID")
15wifi_password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
16
17radio = wifi.radio
18while not radio.connected:
19 radio.connect(wifi_ssid, wifi_password)
20
21# get the pool and ssl_context from the helpers:
22pool = adafruit_connection_manager.get_radio_socketpool(radio)
23ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio)
24
25# get request session
26requests = adafruit_requests.Session(pool, ssl_context)
27connection_manager = adafruit_connection_manager.get_connection_manager(pool)
28print("-" * 40)
29print("Nothing yet opened")
30print(f"Managed Sockets: {connection_manager.managed_socket_count}")
31print(f"Available Managed Sockets: {connection_manager.available_socket_count}")
32
33# make request
34print("-" * 40)
35print(f"Fetching from {TEXT_URL} in a context handler")
36with requests.get(TEXT_URL) as response:
37 response_text = response.text
38 print(f"Text Response {response_text}")
39
40print("-" * 40)
41print("1 request, opened and closed")
42print(f"Managed Sockets: {connection_manager.managed_socket_count}")
43print(f"Available Managed Sockets: {connection_manager.available_socket_count}")
44
45print("-" * 40)
46print(f"Fetching from {TEXT_URL} not in a context handler")
47response = requests.get(TEXT_URL)
48
49print("-" * 40)
50print("1 request, opened but not closed")
51print(f"Managed Sockets: {connection_manager.managed_socket_count}")
52print(f"Available Managed Sockets: {connection_manager.available_socket_count}")
53
54print("-" * 40)
55print("Closing everything in the pool")
56adafruit_connection_manager.connection_manager_close_all(pool)
57
58print("-" * 40)
59print("Everything closed")
60print(f"Managed Sockets: {connection_manager.managed_socket_count}")
61print(f"Available Managed Sockets: {connection_manager.available_socket_count}")
SSL Test¶
This test runs across the common hosts found in the Adafruit Learning System Guides as well as tests created by badssl.com
1# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries
2#
3# SPDX-License-Identifier: Unlicense
4
5import os
6import time
7
8import adafruit_connection_manager
9
10try:
11 import wifi
12
13 radio = wifi.radio
14 onboard_wifi = True
15except ImportError:
16 import board
17 import busio
18 from adafruit_esp32spi import adafruit_esp32spi
19 from digitalio import DigitalInOut
20
21 # esp32spi pins set based on Adafruit AirLift FeatherWing
22 # if using a different setup, please change appropriately
23 spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
24 esp32_cs = DigitalInOut(board.D13)
25 esp32_ready = DigitalInOut(board.D11)
26 esp32_reset = DigitalInOut(board.D12)
27 radio = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
28 onboard_wifi = False
29
30
31# built from:
32# https://github.com/adafruit/Adafruit_Learning_System_Guides
33ADAFRUIT_GROUPS = [
34 {
35 "heading": "API hosts",
36 "description": "These are common API hosts users hit.",
37 "success": "yes",
38 "fail": "no",
39 "subdomains": [
40 {"host": "api.coindesk.com"},
41 {"host": "api.covidtracking.com"},
42 {"host": "api.developer.lifx.com"},
43 {"host": "api.fitbit.com"},
44 {"host": "api.github.com"},
45 {"host": "api.hackaday.io"},
46 {"host": "api.hackster.io"},
47 {"host": "api.met.no"},
48 {"host": "api.nasa.gov"},
49 {"host": "api.nytimes.com"},
50 {"host": "api.open-meteo.com"},
51 {"host": "api.openai.com"},
52 {"host": "api.openweathermap.org"},
53 {"host": "api.purpleair.com"},
54 {"host": "api.spacexdata.com"},
55 {"host": "api.thecatapi.com"},
56 {"host": "api.thingiverse.com"},
57 {"host": "api.thingspeak.com"},
58 {"host": "api.tidesandcurrents.noaa.gov"},
59 {"host": "api.twitter.com"},
60 {"host": "api.wordnik.com"},
61 ],
62 },
63 {
64 "heading": "Common hosts",
65 "description": "These are other common hosts users hit.",
66 "success": "yes",
67 "fail": "no",
68 "subdomains": [
69 {"host": "admiraltyapi.azure-api.net"},
70 {"host": "aeroapi.flightaware.com"},
71 {"host": "airnowapi.org"},
72 {"host": "certification.oshwa.org"},
73 {"host": "certificationapi.oshwa.org"},
74 {"host": "chat.openai.com"},
75 {"host": "covidtracking.com"},
76 {"host": "discord.com"},
77 {"host": "enviro.epa.gov"},
78 {"host": "flightaware.com"},
79 {"host": "hosted.weblate.org"},
80 {"host": "id.twitch.tv"},
81 {"host": "io.adafruit.com"},
82 {"host": "jwst.nasa.gov"},
83 {"host": "management.azure.com"},
84 {"host": "na1.api.riotgames.com"},
85 {"host": "oauth2.googleapis.com"},
86 {"host": "opensky-network.org"},
87 {"host": "opentdb.com"},
88 {"host": "raw.githubusercontent.com"},
89 {"host": "site.api.espn.com"},
90 {"host": "spreadsheets.google.com"},
91 {"host": "twitrss.me"},
92 {"host": "www.adafruit.com"},
93 {"host": "www.alphavantage.co"},
94 {"host": "www.googleapis.com"},
95 {"host": "www.nhc.noaa.gov"},
96 {"host": "www.reddit.com"},
97 {"host": "youtube.googleapis.com"},
98 ],
99 },
100 {
101 "heading": "Known problem hosts",
102 "description": "These are hosts we have run into problems in the past.",
103 "success": "yes",
104 "fail": "no",
105 "subdomains": [
106 {"host": "valid-isrgrootx2.letsencrypt.org"},
107 {"host": "openaccess-api.clevelandart.org"},
108 ],
109 },
110]
111
112# pulled from:
113# https://github.com/chromium/badssl.com/blob/master/domains/misc/badssl.com/dashboard/sets.js
114BADSSL_GROUPS = [
115 {
116 "heading": "Certificate Validation (High Risk)",
117 "description": (
118 "If your browser connects to one of these sites, it could be very easy for an attacker "
119 "to see and modify everything on web sites that you visit."
120 ),
121 "success": "no",
122 "fail": "yes",
123 "subdomains": [
124 {"subdomain": "expired"},
125 {"subdomain": "wrong.host"},
126 {"subdomain": "self-signed"},
127 {"subdomain": "untrusted-root"},
128 ],
129 },
130 {
131 "heading": "Interception Certificates (High Risk)",
132 "description": (
133 "If your browser connects to one of these sites, it could be very easy for an attacker "
134 "to see and modify everything on web sites that you visit. This may be due to "
135 "interception software installed on your device."
136 ),
137 "success": "no",
138 "fail": "yes",
139 "subdomains": [
140 {"subdomain": "superfish"},
141 {"subdomain": "edellroot"},
142 {"subdomain": "dsdtestprovider"},
143 {"subdomain": "preact-cli"},
144 {"subdomain": "webpack-dev-server"},
145 ],
146 },
147 {
148 "heading": "Broken Cryptography (Medium Risk)",
149 "description": (
150 "If your browser connects to one of these sites, an attacker with enough resources may "
151 "be able to see and/or modify everything on web sites that you visit. This is because "
152 "your browser supports connections settings that are outdated and known to have "
153 "significant security flaws."
154 ),
155 "success": "no",
156 "fail": "yes",
157 "subdomains": [
158 {"subdomain": "rc4"},
159 {"subdomain": "rc4-md5"},
160 {"subdomain": "dh480"},
161 {"subdomain": "dh512"},
162 {"subdomain": "dh1024"},
163 {"subdomain": "null"},
164 ],
165 },
166 {
167 "heading": "Legacy Cryptography (Moderate Risk)",
168 "description": (
169 "If your browser connects to one of these sites, your web traffic is probably safe "
170 "from attackers in the near future. However, your connections to some sites might "
171 "not be using the strongest possible security. Your browser may use these settings in "
172 "order to connect to some older sites."
173 ),
174 "success": "maybe",
175 "fail": "yes",
176 "subdomains": [
177 {"subdomain": "tls-v1-0", "port": 1010},
178 {"subdomain": "tls-v1-1", "port": 1011},
179 {"subdomain": "cbc"},
180 {"subdomain": "3des"},
181 {"subdomain": "dh2048"},
182 ],
183 },
184 {
185 "heading": "Domain Security Policies",
186 "description": (
187 "These are special tests for some specific browsers. These tests may be able to tell "
188 "whether your browser uses advanced domain security policy mechanisms (HSTS, HPKP, SCT"
189 ") to detect illegitimate certificates."
190 ),
191 "success": "maybe",
192 "fail": "yes",
193 "subdomains": [
194 {"subdomain": "revoked"},
195 {"subdomain": "pinning-test"},
196 {"subdomain": "no-sct"},
197 ],
198 },
199 {
200 "heading": "Secure (Uncommon)",
201 "description": (
202 "These settings are secure. However, they are less common and even if your browser "
203 "doesn't support them you probably won't have issues with most sites."
204 ),
205 "success": "yes",
206 "fail": "maybe",
207 "subdomains": [
208 {"subdomain": "1000-sans"},
209 {"subdomain": "10000-sans"},
210 {"subdomain": "sha384"},
211 {"subdomain": "sha512"},
212 {"subdomain": "rsa8192"},
213 {"subdomain": "no-subject"},
214 {"subdomain": "no-common-name"},
215 {"subdomain": "incomplete-chain"},
216 ],
217 },
218 {
219 "heading": "Secure (Common)",
220 "description": (
221 "These settings are secure and commonly used by sites. Your browser will need to "
222 "support most of these in order to connect to sites securely."
223 ),
224 "success": "yes",
225 "fail": "no",
226 "subdomains": [
227 {"subdomain": "tls-v1-2", "port": 1012},
228 {"subdomain": "sha256"},
229 {"subdomain": "rsa2048"},
230 {"subdomain": "ecc256"},
231 {"subdomain": "ecc384"},
232 {"subdomain": "extended-validation"},
233 {"subdomain": "mozilla-modern"},
234 ],
235 },
236]
237
238COMMON_FAILURE_CODES = [
239 "Expected 01 but got 00", # AirLift
240 "Failed SSL handshake", # Espressif
241 "MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANG", # mbedtls
242 "MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE", # mbedtls
243 "MBEDTLS_ERR_X509_CERT_VERIFY_FAILED", # mbedtls
244 "MBEDTLS_ERR_X509_FATAL_ERROR", # mbedtls
245]
246
247
248pool = adafruit_connection_manager.get_radio_socketpool(radio)
249ssl_context = adafruit_connection_manager.get_radio_ssl_context(radio)
250connection_manager = adafruit_connection_manager.get_connection_manager(pool)
251
252wifi_ssid = os.getenv("CIRCUITPY_WIFI_SSID")
253wifi_password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
254
255if onboard_wifi:
256 while not radio.connected:
257 radio.connect(wifi_ssid, wifi_password)
258else:
259 while not radio.is_connected:
260 try:
261 radio.connect_AP(wifi_ssid, wifi_password)
262 except OSError as os_exc:
263 print(f"could not connect to AP, retrying: {os_exc}")
264 continue
265
266
267def common_failure(exc):
268 text_value = str(exc)
269 for common_failures_code in COMMON_FAILURE_CODES:
270 if common_failures_code in text_value:
271 return True
272 return False
273
274
275def check_group(groups, group_name):
276 print(f"\nRunning {group_name}")
277 for group in groups:
278 print(f'\n - {group["heading"]}')
279 success = group["success"]
280 fail = group["fail"]
281 for subdomain in group["subdomains"]:
282 if "host" in subdomain:
283 host = subdomain["host"]
284 else:
285 host = f'{subdomain["subdomain"]}.badssl.com'
286 port = subdomain.get("port", 443)
287 exc = None
288 start_time = time.monotonic()
289 try:
290 socket = connection_manager.get_socket(
291 host,
292 port,
293 "https:",
294 is_ssl=True,
295 ssl_context=ssl_context,
296 timeout=10,
297 )
298 connection_manager.close_socket(socket)
299 except RuntimeError as e:
300 exc = e
301 duration = time.monotonic() - start_time
302
303 if fail == "yes" and exc and common_failure(exc):
304 result = "passed"
305 elif success == "yes" and exc is None:
306 result = "passed"
307 else:
308 result = f"error - success:{success}, fail:{fail}, exc:{exc}"
309
310 print(f" - {host}:{port} took {duration:.2f} seconds | {result}")
311
312
313check_group(ADAFRUIT_GROUPS, "Adafruit")
314check_group(BADSSL_GROUPS, "BadSSL")