From 50f0351e555328f85cf7bec0c7c8137497de4abd Mon Sep 17 00:00:00 2001 From: tazlin Date: Thu, 3 Oct 2024 07:52:12 -0400 Subject: [PATCH] fix: use a default `certifi` based ssl context The hope of this change is to fix an issue where uploads to cloudflare on a fresh windows 10 pro machine would fail due to being unable to resolve the system's cert store for the relevant root authority certificate. Despite being sure the cert was installed and various other troubleshooting efforts, only by utilizing certifi to resolve the cert store ultimately resolved the issue. --- horde_sdk/generic_api/generic_clients.py | 14 ++++++++++++++ requirements.txt | 1 + 2 files changed, 15 insertions(+) diff --git a/horde_sdk/generic_api/generic_clients.py b/horde_sdk/generic_api/generic_clients.py index 4a7a6d9..67b3ad5 100644 --- a/horde_sdk/generic_api/generic_clients.py +++ b/horde_sdk/generic_api/generic_clients.py @@ -4,10 +4,13 @@ import asyncio import os +import ssl from abc import ABC +from ssl import SSLContext from typing import Any, TypeVar import aiohttp +import certifi import requests from loguru import logger from pydantic import BaseModel, ValidationError @@ -32,6 +35,9 @@ GenericQueryFields, ) +_default_sslcontext = ssl.create_default_context(cafile=certifi.where()) +"""The default SSL context to use for aiohttp requests.""" + class ParsedRawRequest(BaseModel): """A helper class for passing around the data needed to make an actual web request.""" @@ -59,6 +65,7 @@ class BaseHordeAPIClient(ABC): # region Private Fields _aiohttp_session: aiohttp.ClientSession + _ssl_context: SSLContext _apikey: str | None @@ -82,6 +89,7 @@ def __init__( path_fields: type[GenericPathFields] = GenericPathFields, query_fields: type[GenericQueryFields] = GenericQueryFields, accept_types: type[GenericAcceptTypes] = GenericAcceptTypes, + ssl_context: SSLContext = _default_sslcontext, **kwargs: Any, # noqa: ANN401 ) -> None: """Initialize a new `GenericHordeAPIClient` instance. @@ -104,6 +112,11 @@ def __init__( """ self._apikey = apikey + if not isinstance(ssl_context, SSLContext): + raise TypeError("`ssl_context` must be of type `SSLContext`!") + + self._ssl_context = ssl_context + if not self._apikey: self._apikey = ANON_API_KEY @@ -445,6 +458,7 @@ async def submit_request( params=parsed_request.request_queries, json=parsed_request.request_body, allow_redirects=True, + ssl=self._ssl_context, ) as response, ): raw_response_json = await response.json() diff --git a/requirements.txt b/requirements.txt index 0cfbb28..34a5bbd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ pydantic==2.9.2 requests StrEnum loguru +certifi aiohttp aiofiles aiodns