Skip to content

Commit

Permalink
Introduce async_create_ssl_context (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
dukeofphilberg authored Aug 22, 2024
1 parent 8b15737 commit 127d4c1
Showing 1 changed file with 30 additions and 2 deletions.
32 changes: 30 additions & 2 deletions src/linkplay/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
import os
import socket
import ssl
from concurrent.futures import ThreadPoolExecutor
from http import HTTPStatus
from typing import Dict

import aiofiles
import async_timeout
from aiohttp import ClientError, ClientSession, TCPConnector
from appdirs import AppDirs
from deprecated import deprecated

from linkplay.consts import API_ENDPOINT, API_TIMEOUT, MTLS_CERTIFICATE_CONTENTS
from linkplay.exceptions import LinkPlayRequestException
Expand Down Expand Up @@ -75,6 +77,7 @@ def decode_hexstr(hexstr: str) -> str:
return hexstr


@deprecated(version="0.0.9", reason="Use async_create_unverified_context instead")
def create_unverified_context() -> ssl.SSLContext:
"""Creates an unverified SSL context with the default mTLS certificate."""
dirs = AppDirs("python-linkplay")
Expand All @@ -90,16 +93,38 @@ def create_unverified_context() -> ssl.SSLContext:
return create_ssl_context(path=mtls_certificate_path)


async def async_create_unverified_context() -> ssl.SSLContext:
async def async_create_unverified_context(
executor: ThreadPoolExecutor | None = None,
) -> ssl.SSLContext:
"""Asynchronously creates an unverified SSL context with the default mTLS certificate."""
async with aiofiles.tempfile.NamedTemporaryFile(
"w", encoding="utf-8"
) as mtls_certificate:
await mtls_certificate.write(MTLS_CERTIFICATE_CONTENTS)
await mtls_certificate.flush()
return create_ssl_context(path=str(mtls_certificate.name))
certfile: str = str(mtls_certificate.name)
return await async_create_ssl_context(certfile=certfile, executor=executor)


async def async_create_ssl_context(
*, certfile: str, executor: ThreadPoolExecutor | None = None
) -> ssl.SSLContext:
"""Creates an SSL context from given certificate file."""
sslcontext: ssl.SSLContext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
sslcontext.check_hostname = False
sslcontext.verify_mode = ssl.CERT_NONE

loop = asyncio.get_running_loop()
await loop.run_in_executor(executor, sslcontext.load_cert_chain, certfile)

with contextlib.suppress(AttributeError):
# This only works for OpenSSL >= 1.0.0
sslcontext.options |= ssl.OP_NO_COMPRESSION
sslcontext.set_default_verify_paths()
return sslcontext


@deprecated(version="0.0.9", reason="Use async_create_ssl_context instead")
def create_ssl_context(path: str) -> ssl.SSLContext:
"""Creates an SSL context from given certificate file."""
sslcontext: ssl.SSLContext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
Expand All @@ -113,6 +138,9 @@ def create_ssl_context(path: str) -> ssl.SSLContext:
return sslcontext


@deprecated(
version="0.0.9", reason="Use async_create_unverified_client_session instead"
)
def create_unverified_client_session() -> ClientSession:
"""Creates a ClientSession using the default unverified SSL context"""
context: ssl.SSLContext = create_unverified_context()
Expand Down

0 comments on commit 127d4c1

Please sign in to comment.