+
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
python-version: ["3.10", "3.11", "3.12-dev"]
python-version: ["3.10", "3.11", "3.12", "pypy3.10"]

runs-on: ${{ matrix.os }}
name: ${{ fromJson('{"macos-latest":"macOS","windows-latest":"Windows","ubuntu-latest":"Ubuntu"}')[matrix.os] }} Python ${{ matrix.python-version }}
Expand All @@ -49,9 +49,10 @@ jobs:
uses: actions/checkout@v3

- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true

- name: Setup Go
uses: actions/setup-go@v3
Expand Down
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ authors = [
readme = "README.md"
license = {file = "LICENSE"}
classifiers = [
"Development Status :: 4 - Beta",
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: MacOS",
Expand All @@ -21,6 +21,8 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
dynamic = ["version", "description"]
requires-python = ">= 3.10"
Expand Down
18 changes: 15 additions & 3 deletions src/truststore/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@

import _ssl # type: ignore[import]

from ._ssl_constants import _original_SSLContext, _original_super_SSLContext
from ._ssl_constants import (
_original_SSLContext,
_original_super_SSLContext,
_truststore_SSLContext_dunder_class,
_truststore_SSLContext_super_class,
)

if platform.system() == "Windows":
from ._windows import _configure_context, _verify_peercerts_impl
Expand Down Expand Up @@ -49,9 +54,16 @@ def extract_from_ssl() -> None:
pass


class SSLContext(ssl.SSLContext):
class SSLContext(_truststore_SSLContext_super_class): # type: ignore[misc]
"""SSLContext API that uses system certificates on all platforms"""

@property # type: ignore[misc]
def __class__(self) -> type:
# Dirty hack to get around isinstance() checks
# for ssl.SSLContext instances in aiohttp/trustme
# when using non-CPython implementations.
return _truststore_SSLContext_dunder_class or SSLContext
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you point me to a reproducer for why this was needed for PyPy? Is there something PyPy should be doing to make isinstance work?


def __init__(self, protocol: int = None) -> None: # type: ignore[assignment]
self._ctx = _original_SSLContext(protocol)

Expand Down Expand Up @@ -240,7 +252,7 @@ def protocol(self) -> ssl._SSLMethod:
return self._ctx.protocol

@property
def security_level(self) -> int: # type: ignore[override]
def security_level(self) -> int:
return self._ctx.security_level

@property
Expand Down
19 changes: 19 additions & 0 deletions src/truststore/_ssl_constants.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
import ssl
import sys
import typing

# Hold on to the original class so we can create it consistently
# even if we inject our own SSLContext into the ssl module.
_original_SSLContext = ssl.SSLContext
_original_super_SSLContext = super(_original_SSLContext, _original_SSLContext)

# CPython is known to be good, but non-CPython implementations
# may implement SSLContext differently so to be safe we don't
# subclass the SSLContext.

# This is returned by truststore.SSLContext.__class__()
_truststore_SSLContext_dunder_class: typing.Optional[type]

# This value is the superclass of truststore.SSLContext.
_truststore_SSLContext_super_class: type

if sys.implementation.name == "cpython":
_truststore_SSLContext_super_class = _original_SSLContext
_truststore_SSLContext_dunder_class = None
else:
_truststore_SSLContext_super_class = object
_truststore_SSLContext_dunder_class = _original_SSLContext


def _set_ssl_context_verify_mode(
ssl_context: ssl.SSLContext, verify_mode: ssl.VerifyMode
Expand Down
8 changes: 6 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,13 @@ async def handler(request: web.Request) -> web.Response:
app.add_routes([web.get("/", handler)])

ctx = original_SSLContext(ssl.PROTOCOL_TLS_SERVER)

# We use str(pathlib.Path) here because PyPy doesn't accept Path objects.
# TODO: This is a bug in PyPy and should be reported to them, but their
# GitLab instance was offline when we found this bug. :'(
ctx.load_cert_chain(
certfile=mkcert_certs.cert_file,
keyfile=mkcert_certs.key_file,
certfile=str(mkcert_certs.cert_file),
keyfile=str(mkcert_certs.key_file),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that, is there a simple reproducer for this? PyPy passes the CPython ssl stdlib tests, maybe there is a case missing there?

)

# we need keepalive_timeout=0
Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载