Sync from SUSE:ALP:Source:Standard:1.0 python-Twisted revision 177e11e657250072c4246369fdf6003c

This commit is contained in:
Adrian Schröter 2023-12-22 10:25:21 +01:00
commit 5977523691
17 changed files with 3178 additions and 0 deletions

23
.gitattributes vendored Normal file
View File

@ -0,0 +1,23 @@
## Default LFS
*.7z filter=lfs diff=lfs merge=lfs -text
*.bsp filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gem filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.lzma filter=lfs diff=lfs merge=lfs -text
*.obscpio filter=lfs diff=lfs merge=lfs -text
*.oxt filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.tbz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.txz filter=lfs diff=lfs merge=lfs -text
*.whl filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text

View File

@ -0,0 +1,92 @@
From df79d69adea5c819bb104861dccf1bbe25851644 Mon Sep 17 00:00:00 2001
From: Thomas Grainger <tagrain@gmail.com>
Date: Sun, 21 Feb 2021 11:54:25 +0000
Subject: [PATCH 1/2] delegate to stdlib parse qs
---
src/twisted/web/http.py | 26 +-------------------------
src/twisted/web/newsfragments/10096.bugfix | 1 +
src/twisted/web/server.py | 5 ++---
3 files changed, 4 insertions(+), 28 deletions(-)
create mode 100644 src/twisted/web/newsfragments/10096.bugfix
Index: Twisted-22.1.0/src/twisted/web/http.py
===================================================================
--- Twisted-22.1.0.orig/src/twisted/web/http.py
+++ Twisted-22.1.0/src/twisted/web/http.py
@@ -113,6 +113,7 @@ from urllib.parse import (
ParseResultBytes,
unquote_to_bytes as unquote,
urlparse as _urlparse,
+ parse_qs,
)
from zope.interface import Attribute, Interface, implementer, provider
@@ -263,31 +264,6 @@ def urlparse(url):
return ParseResultBytes(scheme, netloc, path, params, query, fragment)
-def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
- """
- Like C{cgi.parse_qs}, but with support for parsing byte strings on Python 3.
-
- @type qs: C{bytes}
- """
- d = {}
- items = [s2 for s1 in qs.split(b"&") for s2 in s1.split(b";")]
- for item in items:
- try:
- k, v = item.split(b"=", 1)
- except ValueError:
- if strict_parsing:
- raise
- continue
- if v or keep_blank_values:
- k = unquote(k.replace(b"+", b" "))
- v = unquote(v.replace(b"+", b" "))
- if k in d:
- d[k].append(v)
- else:
- d[k] = [v]
- return d
-
-
def datetimeToString(msSinceEpoch=None):
"""
Convert seconds since epoch to HTTP datetime string.
Index: Twisted-22.1.0/src/twisted/web/newsfragments/10096.bugfix
===================================================================
--- /dev/null
+++ Twisted-22.1.0/src/twisted/web/newsfragments/10096.bugfix
@@ -0,0 +1 @@
+delegate to urllib.parse:parse_qs in twisted.web.http:parse_qs to avoid CVE-2021-23336 and the associated CI failures
Index: Twisted-22.1.0/src/twisted/web/server.py
===================================================================
--- Twisted-22.1.0.orig/src/twisted/web/server.py
+++ Twisted-22.1.0/src/twisted/web/server.py
@@ -21,7 +21,7 @@ import zlib
from binascii import hexlify
from html import escape
from typing import List, Optional
-from urllib.parse import quote as _quote
+from urllib.parse import quote as _quote, unquote_to_bytes as _unquote_to_bytes
from zope.interface import implementer
@@ -37,7 +37,6 @@ from twisted.python.deprecate import dep
from twisted.spread.pb import Copyable, ViewPoint
from twisted.web import http, iweb, resource, util
from twisted.web.error import UnsupportedMethod
-from twisted.web.http import unquote
NOT_DONE_YET = 1
@@ -211,7 +210,7 @@ class Request(Copyable, http.Request, co
# Resource Identification
self.prepath = []
- self.postpath = list(map(unquote, self.path[1:].split(b"/")))
+ self.postpath = [_unquote_to_bytes(v) for v in self.path[1:].split(b"/")]
# Short-circuit for requests whose path is '*'.
if self.path == b"*":

View File

@ -0,0 +1,174 @@
---
src/twisted/web/http.py | 32 +++++++++--
src/twisted/web/newsfragments/11976.bugfix | 7 ++
src/twisted/web/test/test_web.py | 81 ++++++++++++++++++++++++++++-
3 files changed, 114 insertions(+), 6 deletions(-)
--- a/src/twisted/web/http.py
+++ b/src/twisted/web/http.py
@@ -2419,14 +2419,38 @@ class HTTPChannel(basic.LineReceiver, po
self._handlingRequest = True
+ # We go into raw mode here even though we will be receiving lines next
+ # in the protocol; however, this data will be buffered and then passed
+ # back to line mode in the setLineMode call in requestDone.
+ self.setRawMode()
+
req = self.requests[-1]
req.requestReceived(command, path, version)
- def dataReceived(self, data):
+ def rawDataReceived(self, data: bytes) -> None:
"""
- Data was received from the network. Process it.
+ This is called when this HTTP/1.1 parser is in raw mode rather than
+ line mode.
+
+ It may be in raw mode for one of two reasons:
+
+ 1. All the headers of a request have been received and this
+ L{HTTPChannel} is currently receiving its body.
+
+ 2. The full content of a request has been received and is currently
+ being processed asynchronously, and this L{HTTPChannel} is
+ buffering the data of all subsequent requests to be parsed
+ later.
+
+ In the second state, the data will be played back later.
+
+ @note: This isn't really a public API, and should be invoked only by
+ L{LineReceiver}'s line parsing logic. If you wish to drive an
+ L{HTTPChannel} from a custom data source, call C{dataReceived} on
+ it directly.
+
+ @see: L{LineReceive.rawDataReceived}
"""
- # If we're currently handling a request, buffer this data.
if self._handlingRequest:
self._dataBuffer.append(data)
if (
@@ -2438,9 +2462,7 @@ class HTTPChannel(basic.LineReceiver, po
# ready. See docstring for _optimisticEagerReadSize above.
self._networkProducer.pauseProducing()
return
- return basic.LineReceiver.dataReceived(self, data)
- def rawDataReceived(self, data):
self.resetTimeout()
try:
--- /dev/null
+++ b/src/twisted/web/newsfragments/11976.bugfix
@@ -0,0 +1,7 @@
+In Twisted 16.3.0, we changed twisted.web to stop dispatching HTTP/1.1
+pipelined requests to application code. There was a bug in this change which
+still allowed clients which could send multiple full HTTP requests in a single
+TCP segment to trigger asynchronous processing of later requests, which could
+lead to out-of-order responses. This has now been corrected and twisted.web
+should never process a pipelined request over HTTP/1.1 until the previous
+request has fully completed.
--- a/src/twisted/web/test/test_web.py
+++ b/src/twisted/web/test/test_web.py
@@ -8,6 +8,7 @@ Tests for various parts of L{twisted.web
import os
import zlib
from io import BytesIO
+from typing import List
from zope.interface import implementer
from zope.interface.verify import verifyObject
@@ -17,10 +18,13 @@ from twisted.internet.address import IPv
from twisted.internet.task import Clock
from twisted.logger import LogLevel, globalLogPublisher
from twisted.python import failure, reflect
+from twisted.python.compat import iterbytes
from twisted.python.filepath import FilePath
-from twisted.test.proto_helpers import EventLoggingObserver
+from twisted.test.proto_helpers import EventLoggingObserver, StringTransport
from twisted.trial import unittest
from twisted.web import error, http, iweb, resource, server
+from twisted.web.resource import Resource
+from twisted.web.server import NOT_DONE_YET, Request, Site
from twisted.web.static import Data
from twisted.web.test.requesthelper import DummyChannel, DummyRequest
from ._util import assertIsFilesystemTemporary
@@ -1849,3 +1853,78 @@ class ExplicitHTTPFactoryReactor(unittes
factory = http.HTTPFactory()
self.assertIs(factory.reactor, reactor)
+
+
+class QueueResource(Resource):
+ """
+ Add all requests to an internal queue,
+ without responding to the requests.
+ You can access the requests from the queue and handle their response.
+ """
+
+ isLeaf = True
+
+ def __init__(self) -> None:
+ super().__init__()
+ self.dispatchedRequests: List[Request] = []
+
+ def render_GET(self, request: Request) -> int:
+ self.dispatchedRequests.append(request)
+ return NOT_DONE_YET
+
+
+class TestRFC9112Section932(unittest.TestCase):
+ """
+ Verify that HTTP/1.1 request ordering is preserved.
+ """
+
+ def test_multipleRequestsInOneSegment(self) -> None:
+ """
+ Twisted MUST NOT respond to a second HTTP/1.1 request while the first
+ is still pending.
+ """
+ qr = QueueResource()
+ site = Site(qr)
+ proto = site.buildProtocol(None)
+ serverTransport = StringTransport()
+ proto.makeConnection(serverTransport)
+ proto.dataReceived(
+ b"GET /first HTTP/1.1\r\nHost: a\r\n\r\n"
+ b"GET /second HTTP/1.1\r\nHost: a\r\n\r\n"
+ )
+ # The TCP data contains 2 requests,
+ # but only 1 request was dispatched,
+ # as the first request was not yet finalized.
+ self.assertEqual(len(qr.dispatchedRequests), 1)
+ # The first request is finalized and the
+ # second request is dispatched right away.
+ qr.dispatchedRequests[0].finish()
+ self.assertEqual(len(qr.dispatchedRequests), 2)
+
+ def test_multipleRequestsInDifferentSegments(self) -> None:
+ """
+ Twisted MUST NOT respond to a second HTTP/1.1 request while the first
+ is still pending, even if the second request is received in a separate
+ TCP package.
+ """
+ qr = QueueResource()
+ site = Site(qr)
+ proto = site.buildProtocol(None)
+ serverTransport = StringTransport()
+ proto.makeConnection(serverTransport)
+ raw_data = (
+ b"GET /first HTTP/1.1\r\nHost: a\r\n\r\n"
+ b"GET /second HTTP/1.1\r\nHost: a\r\n\r\n"
+ )
+ # Just go byte by byte for the extreme case in which each byte is
+ # received in a separate TCP package.
+ for chunk in iterbytes(raw_data):
+ proto.dataReceived(chunk)
+ # The TCP data contains 2 requests,
+ # but only 1 request was dispatched,
+ # as the first request was not yet finalized.
+ self.assertEqual(len(qr.dispatchedRequests), 1)
+ # The first request is finalized and the
+ # second request is dispatched right away.
+ qr.dispatchedRequests[0].finish()
+ self.assertEqual(len(qr.dispatchedRequests), 2)

BIN
Twisted-22.10.0.tar.gz (Stored with Git LFS) Normal file

Binary file not shown.

3
_multibuild Normal file
View File

@ -0,0 +1,3 @@
<multibuild>
<package>test</package>
</multibuild>

View File

@ -0,0 +1,18 @@
---
src/twisted/test/test_failure.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: Twisted-22.10.0/src/twisted/test/test_failure.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/test/test_failure.py
+++ Twisted-22.10.0/src/twisted/test/test_failure.py
@@ -16,7 +16,8 @@ from io import StringIO
from traceback import FrameSummary
from unittest import skipIf
-from cython_test_exception_raiser import raiser # type: ignore[import]
+# from cython_test_exception_raiser import raiser # type: ignore[import]
+raiser = None
from twisted.python import failure, reflect
from twisted.trial.unittest import SynchronousTestCase

36
no-pygtkcompat.patch Normal file
View File

@ -0,0 +1,36 @@
Index: Twisted-22.10.0/src/twisted/internet/gireactor.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/internet/gireactor.py
+++ Twisted-22.10.0/src/twisted/internet/gireactor.py
@@ -21,20 +21,24 @@ On Python 3, pygobject v3.4 or later is
"""
-import gi.pygtkcompat # type: ignore[import]
from gi.repository import GLib # type: ignore[import]
from twisted.internet import _glibbase
from twisted.internet.error import ReactorAlreadyRunning
from twisted.python import runtime
-# We require a sufficiently new version of pygobject, so always exists:
-_pygtkcompatPresent = True
+try:
+ import gi.pygtkcompat # type: ignore[import]
+except ImportError:
+ pass # This is probably Python 3, with pygtkcompat removed
+else:
+ # We require a sufficiently new version of pygobject, so always exists:
+ _pygtkcompatPresent = True
-# Newer version of gi, so we can try to initialize compatibility layer; if
-# real pygtk was already imported we'll get ImportError at this point
-# rather than segfault, so unconditional import is fine.
-gi.pygtkcompat.enable()
+ # Newer version of gi, so we can try to initialize compatibility layer; if
+ # real pygtk was already imported we'll get ImportError at this point
+ # rather than segfault, so unconditional import is fine.
+ gi.pygtkcompat.enable()
# At this point importing gobject will get you gi version, and importing
# e.g. gtk will either fail in non-segfaulty way or use gi version if user
# does gi.pygtkcompat.enable_gtk(). So, no need to prevent imports of

View File

@ -0,0 +1,25 @@
---
src/twisted/conch/test/test_keys.py | 3 +++
1 file changed, 3 insertions(+)
Index: Twisted-22.10.0/src/twisted/conch/test/test_keys.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/conch/test/test_keys.py
+++ Twisted-22.10.0/src/twisted/conch/test/test_keys.py
@@ -15,6 +15,7 @@ from twisted.python import randbytes
from twisted.python.filepath import FilePath
from twisted.python.reflect import requireModule
from twisted.trial import unittest
+import unittest as pyunit
cryptography = requireModule("cryptography")
if cryptography is None:
@@ -259,6 +260,8 @@ class KeyTests(unittest.TestCase):
for k, v in data.items():
self.assertEqual(privateKey.data()[k], v)
+ @pyunit.skip('Upstream ticket https://twistedmatrix.com/trac/ticket/9665' +
+ ' has still not been resolved.')
def test_fromOpenSSH(self):
"""
Test that keys are correctly generated from OpenSSH strings.

117
py311-tests-compat.patch Normal file
View File

@ -0,0 +1,117 @@
Index: Twisted-22.10.0/src/twisted/newsfragments/10343.feature
===================================================================
--- /dev/null
+++ Twisted-22.10.0/src/twisted/newsfragments/10343.feature
@@ -0,0 +1 @@
+Twisted now officially supports Python 3.11.
Index: Twisted-22.10.0/src/twisted/persisted/aot.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/persisted/aot.py
+++ Twisted-22.10.0/src/twisted/persisted/aot.py
@@ -399,8 +399,10 @@ class AOTUnjellier:
inst = klass.__new__(klass)
if hasattr(klass, "__setstate__"):
self.callAfter(inst.__setstate__, state)
- else:
+ elif isinstance(state, dict):
inst.__dict__ = state
+ else:
+ inst.__dict__ = state.__getstate__()
return inst
elif c is Ref:
Index: Twisted-22.10.0/src/twisted/spread/flavors.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/spread/flavors.py
+++ Twisted-22.10.0/src/twisted/spread/flavors.py
@@ -398,6 +398,8 @@ class RemoteCopy(Unjellyable):
object's dictionary (or a filtered approximation of it depending
on my peer's perspective).
"""
+ if not state:
+ state = {}
state = {
x.decode("utf8") if isinstance(x, bytes) else x: y for x, y in state.items()
}
Index: Twisted-22.10.0/src/twisted/spread/jelly.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/spread/jelly.py
+++ Twisted-22.10.0/src/twisted/spread/jelly.py
@@ -154,7 +154,8 @@ def _newInstance(cls, state):
instance = _createBlank(cls)
def defaultSetter(state):
- instance.__dict__ = state
+ if isinstance(state, dict):
+ instance.__dict__ = state or {}
setter = getattr(instance, "__setstate__", defaultSetter)
setter(state)
Index: Twisted-22.10.0/src/twisted/test/test_persisted.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/test/test_persisted.py
+++ Twisted-22.10.0/src/twisted/test/test_persisted.py
@@ -378,6 +378,10 @@ class AOTTests(TestCase):
def __dict__(self):
raise AttributeError()
+ @property
+ def __getstate__(self):
+ raise AttributeError()
+
self.assertRaises(TypeError, aot.jellyToSource, UnknownType())
def test_basicIdentity(self):
Index: Twisted-22.10.0/src/twisted/trial/test/test_pyunitcompat.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/trial/test/test_pyunitcompat.py
+++ Twisted-22.10.0/src/twisted/trial/test/test_pyunitcompat.py
@@ -218,8 +218,10 @@ class PyUnitResultTests(SynchronousTestC
pyresult = pyunit.TestResult()
result = PyUnitResultAdapter(pyresult)
result.addError(self, f)
+ tback = "".join(traceback.format_exception(*exc_info))
self.assertEqual(
- pyresult.errors[0][1], "".join(traceback.format_exception(*exc_info))
+ pyresult.errors[0][1].endswith("ZeroDivisionError: division by zero\n"),
+ tback.endswith("ZeroDivisionError: division by zero\n"),
)
def test_trialSkip(self):
Index: Twisted-22.10.0/src/twisted/web/test/test_flatten.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/web/test/test_flatten.py
+++ Twisted-22.10.0/src/twisted/web/test/test_flatten.py
@@ -706,15 +706,15 @@ class FlattenerErrorTests(SynchronousTes
Exception while flattening:
\\[<unrenderable>\\]
<unrenderable>
- .*
+ <Deferred at .* current result: <twisted.python.failure.Failure builtins.RuntimeError: example>>
File ".*", line \\d*, in _flattenTree
- element = await element
- RuntimeError: example
+ element = await element.*
"""
),
flags=re.MULTILINE,
),
)
+ self.assertIn("RuntimeError: example", str(failure.value))
# The original exception is unmodified and will be logged separately if
# unhandled.
self.failureResultOf(failing, RuntimeError)
Index: Twisted-22.10.0/src/twisted/mail/test/test_smtp.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/mail/test/test_smtp.py
+++ Twisted-22.10.0/src/twisted/mail/test/test_smtp.py
@@ -1771,7 +1771,8 @@ class SendmailTests(TestCase):
The default C{reactor} parameter of L{twisted.mail.smtp.sendmail} is
L{twisted.internet.reactor}.
"""
- args, varArgs, keywords, defaults = inspect.getargspec(smtp.sendmail)
+ fullSpec = inspect.getfullargspec(smtp.sendmail)
+ defaults = fullSpec[3]
self.assertEqual(reactor, defaults[2])
def _honorsESMTPArguments(self, username, password):

1448
python-Twisted.changes Normal file

File diff suppressed because it is too large Load Diff

1
python-Twisted.rpmlintrc Normal file
View File

@ -0,0 +1 @@
addFilter("E: python-tests-in-package.*/usr/lib/.*/site-packages/twisted.*/test")

306
python-Twisted.spec Normal file
View File

@ -0,0 +1,306 @@
#
# spec file
#
# Copyright (c) 2023 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
%global flavor @BUILD_FLAVOR@%{nil}
%if "%{flavor}" == "test"
%bcond_without test
%define psuffix -test
%else
%bcond_with test
%define psuffix %{nil}
%endif
%define skip_python2 1
%{?sle15_python_module_pythons}
Name: python-Twisted%{psuffix}
Version: 22.10.0
Release: 0
Summary: An asynchronous networking framework written in Python
License: MIT
URL: https://twistedmatrix.com/
Source0: https://files.pythonhosted.org/packages/source/T/Twisted/Twisted-%{version}.tar.gz
Source99: python-Twisted.rpmlintrc
Patch0: skip_MultiCast.patch
# PATCH-FIX-UPSTREAM no-test_successResultOfWithFailureHasTraceback.patch https://twistedmatrix.com/trac/ticket/9665 mcepl@suse.com
# skip over the test test_successResultOfWithFailureHasTraceback
Patch2: no-test_successResultOfWithFailureHasTraceback.patch
# PATCH-FIX-UPSTREAM 1521_delegate_parseqs_stdlib_bpo42967.patch https://twistedmatrix.com/trac/ticket/10096 mcepl@suse.com
# overcome incompatibility with the solution for bpo#42967.
Patch3: 1521_delegate_parseqs_stdlib_bpo42967.patch
# We don't want to package yet another module, and it is easily skippable
Patch4: no-cython_test_exception_raiser.patch
# boo#1110669 Our variant of PyGObject has pygtkcompat stripped which Twisted does not handle
Patch5: no-pygtkcompat.patch
# PATCH-FIX-OPENSUSE remove-dependency-version-upper-bounds.patch boo#1190036 -- run with h2 >= 4.0.0 and priority >= 2.0
Patch6: remove-dependency-version-upper-bounds.patch
# PATCH-FIX-UPSTREAM py311-tests-compat.patch gh#twisted/twisted#11734 gh#twisted/twisted#11733
Patch7: py311-tests-compat.patch
# PATCH-FIX-UPSTREAM gh#twisted/twisted#11787
Patch8: support-new-glibc.patch
# PATCH-FIX-UPSTREAM gh#twisted/twisted#11878
Patch9: regenerate-cert-to-work-with-latest-service-identity.patch
# PATCH-FIX-UPSTREAM gh#twisted/twisted#11873
Patch10: remove-pynacl-optional-dependency.patch
# PATCH-FIX-UPSTREAM CVE-2023-46137-HTTP-pipeline-response.patch bsc#1216588 mcepl@suse.com
# disordered HTTP pipeline response in twisted.web
Patch11: CVE-2023-46137-HTTP-pipeline-response.patch
BuildRequires: %{python_module incremental >= 21.3.0}
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: git-core
BuildRequires: python-rpm-macros
Requires(post): update-alternatives
Requires(postun):update-alternatives
# SECTION install requires
Requires: python-Automat >= 0.8.0
Requires: python-attrs >= 19.2.0
Requires: python-constantly >= 15.1
Requires: python-hyperlink >= 17.1.1
Requires: python-incremental >= 21.3.0
Requires: python-typing_extensions >= 3.6.5
Requires: python-zope.interface >= 4.4.2
# /SECTION
# twisted[tls] is so common, let's keep it tied to the main package for the time being.
Requires: python-Twisted-tls = %{version}
%if %{with test}
BuildRequires: %{python_module Twisted-all_non_platform = %{version}}
BuildRequires: %{python_module Twisted-conch_nacl = %{version}}
# declared nowhere but required to pass 8 tests with timezone checks
BuildRequires: %{python_module pytz}
BuildRequires: %{python_module hypothesis}
%endif
BuildArch: noarch
%python_subpackages
%description
An extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
%if 0%{?suse_version} > 1500
%package -n %{name}-doc
Summary: An asynchronous networking framework written in Python - Documentation
%description -n %{name}-doc
An extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
This package contains the documentation for python-Twisted
%endif
%package tls
Summary: TLS support for Twisted
Requires: python-Twisted = %{version}
Requires: python-idna >= 2.4
Requires: python-pyOpenSSL >= 16.0.0
Requires: python-service_identity >= 18.1.0
%description tls
Twisted is an extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
This metapackage is for the optional feature tls
%package conch
Summary: Conch for Twisted
Requires: python-Twisted = %{version}
Requires: python-appdirs >= 1.4.0
Requires: python-bcrypt >= 3.0.0
Requires: python-cryptography >= 2.6
Requires: python-pyasn1
%description conch
Twisted is an extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
Twisted Conch: The Twisted Shell. Terminal emulation, SSHv2 and telnet.
%package conch_nacl
Summary: Conch w/ NaCl for Twisted
Requires: python-Twisted-conch = %{version}
%description conch_nacl
Twisted is an extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
%package serial
Summary: Serial support for Twisted
Requires: python-Twisted = %{version}
Requires: python-pyserial >= 3.0
%description serial
Twisted is an extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
This metapackage is for the optional feature serial
%package http2
Summary: HTTP/2 support for Twisted
Requires: python-Twisted = %{version}
Requires: python-h2 >= 3.0
Requires: python-priority >= 1.1.0
%description http2
Twisted is an extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
This metapackage is for the optional feature http2
%package contextvars
Summary: Contextvars extra for Twisted
Requires: python-Twisted = %{version}
%description contextvars
Twisted is an extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
This metapackage is for the optional dependency contextvars
%package all_non_platform
Summary: The all_non_platform dependency extra for Twisted
Requires: python-PyHamcrest >= 1.9.0
Requires: python-Twisted-conch = %{version}
Requires: python-Twisted-contextvars = %{version}
Requires: python-Twisted-http2 = %{version}
Requires: python-Twisted-serial = %{version}
Requires: python-Twisted-tls = %{version}
%description all_non_platform
Twisted is an extensible framework for Python programming, with special focus
on event-based network programming and multiprotocol integration.
This metapackage is for the optional dependency all_non_platform
%prep
%autosetup -p1 -n Twisted-%{version}
sed -i '1{/env python/d}' src/twisted/mail/test/pop3testserver.py src/twisted/trial/test/scripttest.py
%if ! %{with test}
%build
%python_build
# empty files
rm docs/{fun/Twisted.Quotes,_static/.placeholder,_templates/.placeholder}
%fdupes docs
%endif
%if ! %{with test}
%install
%python_install
find %{buildroot} -regex '.*\.[ch]' -exec rm {} ";" # Remove leftover C sources
install -dm0755 %{buildroot}%{_mandir}/man1/
install -m0644 docs/*/man/*.1 %{buildroot}%{_mandir}/man1/ # Install man pages
find docs -type f -print0 | xargs -0 chmod a-x # Fix doc-file dependency by removing x flags
#sed -i "s/\r//" docs/core/howto/listings/udp/{MulticastClient,MulticastServer}.py
%python_expand %fdupes %{buildroot}%{$python_sitelib}
# Prepare for update-alternatives usage
for p in twistd cftp ckeygen conch pyhtmlizer tkconch trial ; do
%python_clone -a %{buildroot}%{_bindir}/$p
%python_clone -a %{buildroot}%{_mandir}/man1/$p.1
done
# mailmail is useful only on Python 2
rm %{buildroot}%{_bindir}/mailmail %{buildroot}%{_mandir}/man1/mailmail.1
# no manpage for twist yet:
%python_clone -a %{buildroot}%{_bindir}/twist
%endif
%if %{with test}
%check
export LANG=en_US.UTF-8
export PYTHONDONTWRITEBYTECODE=1
%{python_expand # provide flavored commands for testing
# (= python_flavored_alternatives from gh#openSUSE/python-rpm-macros#120, but sadly not available for non-TW)
mkdir -p build/bin/
for f in %{buildroot}%{_bindir}/*-%{$python_bin_suffix}; do
ln -s $f build/bin/$(basename ${f%%%%-%{$python_bin_suffix}})
done
}
export PATH=$PWD/build/bin/:$PATH
# Relax the crypto policies for the test-suite
export OPENSSL_SYSTEM_CIPHERS_OVERRIDE=xyz_nonexistent_file
export OPENSSL_CONF=''
%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib} $python -m twisted.trial twisted
%endif
%post
# these were master alternatives until Dec 2020. Remove before the install as slave links
for f in cftp ckeygen conch pyhtmlizer tkconch trial twist; do
(update-alternatives --quiet --list $f 2>&1 >/dev/null) && update-alternatives --quiet --remove-all $f
done
%{python_install_alternative twistd cftp ckeygen conch pyhtmlizer tkconch trial twist
twistd.1 cftp.1 ckeygen.1 conch.1 pyhtmlizer.1 tkconch.1 trial.1}
%postun
%python_uninstall_alternative twistd
%if ! %{with test}
%files %{python_files tls}
%license LICENSE
%files %{python_files conch}
%license LICENSE
%files %{python_files conch_nacl}
%license LICENSE
%files %{python_files serial}
%license LICENSE
%files %{python_files http2}
%license LICENSE
%files %{python_files contextvars}
%license LICENSE
%files %{python_files all_non_platform}
%license LICENSE
%files %{python_files}
%license LICENSE
%doc NEWS.rst README.rst
%python_alternative %{_bindir}/conch
%python_alternative %{_bindir}/tkconch
%python_alternative %{_mandir}/man1/conch.1%{?ext_man}
%python_alternative %{_mandir}/man1/tkconch.1%{?ext_man}
%python_alternative %{_bindir}/twistd
%python_alternative %{_bindir}/cftp
%python_alternative %{_bindir}/ckeygen
%python_alternative %{_bindir}/pyhtmlizer
%python_alternative %{_bindir}/trial
%python_alternative %{_bindir}/twist
%python_alternative %{_mandir}/man1/twistd.1%{?ext_man}
%python_alternative %{_mandir}/man1/cftp.1%{?ext_man}
%python_alternative %{_mandir}/man1/ckeygen.1%{?ext_man}
%python_alternative %{_mandir}/man1/pyhtmlizer.1%{?ext_man}
%python_alternative %{_mandir}/man1/trial.1%{?ext_man}
%{python_sitelib}/twisted
%{python_sitelib}/Twisted-%{version}*-info
%if 0%{?suse_version} > 1500
%files -n %{name}-doc
%endif
%doc docs/
%endif
%changelog

View File

@ -0,0 +1,413 @@
From 001fd99f209dce1ee853df87fc4e0627db3bc930 Mon Sep 17 00:00:00 2001
From: Glyph <code@glyph.im>
Date: Wed, 14 Jun 2023 13:41:33 -0700
Subject: [PATCH 1/4] regenerate certificate to work with latest
service_identity
also rewrite all the logic using cryptography rather than pyopenssl
---
src/twisted/newsfragments/11877.misc | 0
src/twisted/test/cert.pem.no_trailing_newline | 40 ++--
src/twisted/test/key.pem.no_trailing_newline | 55 +++---
src/twisted/test/server.pem | 178 ++++++++++--------
4 files changed, 150 insertions(+), 123 deletions(-)
create mode 100644 src/twisted/newsfragments/11877.misc
diff --git a/src/twisted/newsfragments/11877.misc b/src/twisted/newsfragments/11877.misc
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/twisted/test/cert.pem.no_trailing_newline b/src/twisted/test/cert.pem.no_trailing_newline
index 59f1bae563e..11eb4db8119 100644
--- a/src/twisted/test/cert.pem.no_trailing_newline
+++ b/src/twisted/test/cert.pem.no_trailing_newline
@@ -1,23 +1,25 @@
-----BEGIN CERTIFICATE-----
-MIID6DCCAtACAwtEVjANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMCVFIxDzAN
-BgNVBAgMBsOHb3J1bTEUMBIGA1UEBwwLQmHFn21ha8OnxLExEjAQBgNVBAMMCWxv
-Y2FsaG9zdDEcMBoGA1UECgwTVHdpc3RlZCBNYXRyaXggTGFiczEkMCIGA1UECwwb
-QXV0b21hdGVkIFRlc3RpbmcgQXV0aG9yaXR5MSkwJwYJKoZIhvcNAQkBFhpzZWN1
-cml0eUB0d2lzdGVkbWF0cml4LmNvbTAgFw0yMjA4MjMyMzUyNTJaGA8yMTIyMDcz
-MDIzNTI1MlowgbcxCzAJBgNVBAYTAlRSMQ8wDQYDVQQIDAbDh29ydW0xFDASBgNV
-BAcMC0JhxZ9tYWvDp8SxMRIwEAYDVQQDDAlsb2NhbGhvc3QxHDAaBgNVBAoME1R3
+MIIEJDCCAwygAwIBAgIUKaSXgzt5gDMt9GbUzLz/A9HEyFEwDQYJKoZIhvcNAQEL
+BQAwgb0xGDAWBgNVBAMMD0EgSG9zdCwgTG9jYWxseTELMAkGA1UEBhMCVFIxDzAN
+BgNVBAgMBsOHb3J1bTEUMBIGA1UEBwwLQmHFn21ha8OnxLExHDAaBgNVBAoME1R3
aXN0ZWQgTWF0cml4IExhYnMxJDAiBgNVBAsMG0F1dG9tYXRlZCBUZXN0aW5nIEF1
dGhvcml0eTEpMCcGCSqGSIb3DQEJARYac2VjdXJpdHlAdHdpc3RlZG1hdHJpeC5j
-b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9Gk1skmQfONi+GdM2
-Rwb6a/2weSX7eM3MwT3vXYr+0dx9ScWERILTNkLGrvfslHKdUE7hBDKjtuj6KtAI
-rVjeDDMD6Ue77EcbL3QEO1QZeBjJ3hQbaB447PhE1wwgEsWndPMcDDVm93sODELN
-rzWMLhabgCJ5cJYo5RQs7IvVtE36KaoSgfC9rTP8Lva+MW5wNeHn2f0hDlUF8jLu
-o1W+eDb9CHV7vwL19DZ3w74UkQ3RnfNDnZzVhsNI4YGaSBGtOHY3ioDspGQZqHHf
-CSTjjMwq3ddEkPd7iNu4N5KUamnH69A0JfRODC8tXjFG9/WFROhYZkUQRhXkgRd3
-9Yy9AgMBAAEwDQYJKoZIhvcNAQELBQADggEBABuOxiDnfrjQjbP4ZWrDj+doK8Zk
-CUwtyM3gFVF1LBZxBCxVa6hzD2N7/1o0+KHjmiGks7SnXb6aG2nEqypciZ4xkPjt
-wVIcTWCW8ddPrfMi4/esiQFlPck1p3QSfkPiAgHAjJiDDqDtqsMKr+5AkUaHlqjR
-VV3YE27x/QyLZbV7igiTPdh1fTV7+Yl8VHpBdnMRUVTFoZaIiCe0efmqsvzBd73A
-c75aKTwu6cPQ9dH/gIEOHCvrgweED7ZcabT7h/k7DXL2zhnJTPmQSJLWjfQebJOu
-4l1p7tn35xbjqu906l4iII+YqWCAj/gNT2qdcIWQmxg/reg2tRbU7Nv3M0c=
+b20wIBcNMjMwNjE0MTM0MDI4WhgPMjEyMzA1MjExMzQwMjhaMIG9MRgwFgYDVQQD
+DA9BIEhvc3QsIExvY2FsbHkxCzAJBgNVBAYTAlRSMQ8wDQYDVQQIDAbDh29ydW0x
+FDASBgNVBAcMC0JhxZ9tYWvDp8SxMRwwGgYDVQQKDBNUd2lzdGVkIE1hdHJpeCBM
+YWJzMSQwIgYDVQQLDBtBdXRvbWF0ZWQgVGVzdGluZyBBdXRob3JpdHkxKTAnBgkq
+hkiG9w0BCQEWGnNlY3VyaXR5QHR3aXN0ZWRtYXRyaXguY29tMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0rT5+hF+1BjE7qXms9PZWHskXZGXLPiYVmiY
+jsVeJAOtHAYq8igzA49KgR1xR9M4jQ6U46nwPsnGCh4liyxdWkBLw9maxMoE+r6d
+W1zZ8Tllunbdb/Da6L8P55SKb7QGet4CB1fZ2SqZD4GvTby6xpoR09AqrfjuEIYR
+8V/y+8dG3mR5W0HqaJ58IWihAwIQSakuc8jTadJY55t7UW6Ebj2X2WTO6Zh7gJ1d
+yHPMVkUHJF9Jsuj/4F4lx6hWGQzWO8Nf8Q7t364pagE3evUv/BECJLONNYLaFjLt
+WnsCEJDV9owCjaxu785KuA7OM/f3h3xVIfTBTo2AlHiQnXdyrwIDAQABoxgwFjAU
+BgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAEHAErq/Fs8h
+M+kwGCt5Ochqyu/IzPbwgQ27n5IJehl7kmpoXBxGa/u+ajoxrZaOheg8E2MYVwQi
+FTKE9wJgaN3uGo4bzCbCYxDm7tflQORo6QOZlumfiQIzXON2RvgJpwFfkLNtq0t9
+e453kJ7+e11Wah46bc3RAvBZpwswh6hDv2FvFUZ+IUcO0tU8O4kWrLIFPpJbcHQq
+wezjky773X4CNEtoeuTb8/ws/eED/TGZ2AZO+BWT93OZJgwE2x3iUd3k8HbwxfoY
+bZ+NHgtM7iKRcL59asB0OMi3Ays0+IOfZ1+3aB82zYlxFBoDyalR7NJjJGdTwNFt
+3CPGCQ28cDk=
-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/src/twisted/test/key.pem.no_trailing_newline b/src/twisted/test/key.pem.no_trailing_newline
index 63845f8249f..5d489fd73ac 100644
--- a/src/twisted/test/key.pem.no_trailing_newline
+++ b/src/twisted/test/key.pem.no_trailing_newline
@@ -1,28 +1,27 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9Gk1skmQfONi+
-GdM2Rwb6a/2weSX7eM3MwT3vXYr+0dx9ScWERILTNkLGrvfslHKdUE7hBDKjtuj6
-KtAIrVjeDDMD6Ue77EcbL3QEO1QZeBjJ3hQbaB447PhE1wwgEsWndPMcDDVm93sO
-DELNrzWMLhabgCJ5cJYo5RQs7IvVtE36KaoSgfC9rTP8Lva+MW5wNeHn2f0hDlUF
-8jLuo1W+eDb9CHV7vwL19DZ3w74UkQ3RnfNDnZzVhsNI4YGaSBGtOHY3ioDspGQZ
-qHHfCSTjjMwq3ddEkPd7iNu4N5KUamnH69A0JfRODC8tXjFG9/WFROhYZkUQRhXk
-gRd39Yy9AgMBAAECggEAIvGt1f7VRpm8H6DpEVIdvX/gMNCqTqZ7rTcWaVmpWj5Q
-lsxflfoNDNetjkZ95PdnmJ9i/BzI+MzPj48Cw1+5GMs7UCE3EshuOV1S/Ic0GsLB
-HeiOYaQjVZSgqiPtBy5A3Rl05T1yTtUzpZxpadXTONS5c8HBXRyLewId8NFDY9ls
-76PYRq4ui7QGOmXw7VAVzg/7RxcupuSkecE7472Ek1jtEdRdplBga/XE5/+FZhrr
-NyAdVo/1VD8zpaenWiBgfqJTVc/VRBaE0kLa777E++ruqGGz/c5cQPOWzEp0vPbi
-kXz16X2TQDeTe6QfBBYjzD2+LyJh2TXfRtEn56MtJwKBgQDaTzHFOoiPS0+JpOBH
-yW2gIFigEH70Hi++m0okmewGLTGrjOsIVWx8u5QFMANEYXeXIT7sM1eyONYjtxNC
-gpeLyyN9zTyLPWdx3CzNodY2Dg/irTZtPQp7/efAHcn7kW8V0OxCGTyXAzdhKXmN
-thN9KMk6peQMU8L4FqypNznFrwKBgQDdwD0NBxqNk3/Q/qih2EJUOO7uuPAZnTJf
-neRnY4Pc94ticdQbd03ZArP3ybl9wWy+Ri9D+I9P753Hyfb7BSKwwIyYRgxSjGU/
-wqcmv0V/mSY7N4eCDaXqEjdovaZ76d3L60FPH5rJbn7yHZBYWaSqXgk0HDYUmQwg
-huPLNu8bUwKBgQCH/rGohbAwY9/mhRlaXva1u7C59czAUlW3zZFAf8pyhpDcp2p6
-xIxSn5+0I5bFcFpJgWJrTgihc5qioReUZTn20dMIOWQv8U6RtXELoHeLMPNgaDrx
-jgcL+r32BhifaJfk5UNoYcRG5rAHDQk16Gj3nQLOUC1iKIPafHWO7GJG7QKBgQCj
-yVfOhY6xP17K6S14zRjAyISCQorlAFyyjxai3rgIv7Zt8hFucAJJ5Vs0DAU7w2Ak
-cgZ7N93ydtOdO6l24uYqky3FUwfK+PPX0lhPoDse8elxF6S5BIeliervLBUJtUUj
-VxIX9QoI+do9zmRNPXkIdQhrOuMe96Qjaj5aXKrjDQKBgBS2LGghCFgqaxtHeIpl
-RLOnpxLaiitGH412O6VKHkkXaNYEOlbtFVlPuE1zHeyIvLQb666lW/w0+HMmfMTU
-SQI2gIndUb6pMzLjZUrCyYz618EoAmhx6+VnbRSY+iSEIdYqx6VBl0HY9RWJa18H
-4LPzH6dfRnKf2jCer3DtWALD
------END PRIVATE KEY-----
\ No newline at end of file
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA0rT5+hF+1BjE7qXms9PZWHskXZGXLPiYVmiYjsVeJAOtHAYq
+8igzA49KgR1xR9M4jQ6U46nwPsnGCh4liyxdWkBLw9maxMoE+r6dW1zZ8Tllunbd
+b/Da6L8P55SKb7QGet4CB1fZ2SqZD4GvTby6xpoR09AqrfjuEIYR8V/y+8dG3mR5
+W0HqaJ58IWihAwIQSakuc8jTadJY55t7UW6Ebj2X2WTO6Zh7gJ1dyHPMVkUHJF9J
+suj/4F4lx6hWGQzWO8Nf8Q7t364pagE3evUv/BECJLONNYLaFjLtWnsCEJDV9owC
+jaxu785KuA7OM/f3h3xVIfTBTo2AlHiQnXdyrwIDAQABAoH/Ib7aSjKDHXTaFV58
+lFBZftI6AMJQc+Ncgno99J+ndB0inFpghmfpw6gvRn5wphAt/mlXbx7IW0X1cali
+WefBC7NAbx1qrBmusnnUuc0lGn0WzcY7sLHiXWQ8J9qiUUGDyCnGKWbofN9VpCYg
+7VJMl4IVWNb9/t7fQcY3GXFEeQ4mzLo7p+gPxyeUcCLVrhVrHzw1HFTIlA51LjfI
+xQM+QVeaEWQQ4UsDdPe5iGthDd7ze2F5ciDzMkShrf7URSudS+Us6vr6gDVpKAky
+eCVyFPJXCfH4qJoa6mB6L6SFzMnN3OPp3RlYQWQ7sK/ELQfhPoyHyRvL1woUIO5C
+tK0pAoGBAPS6ZSZ26M0guZ2K/2fKMiGq0jZQLcxP3N0jWm8R8ENOnuIjhCl5aKsB
+DoV0BvPv1C2vWm+VgNArgTece9l8o5f8pcfjbT5r/k8zoqgcj9CmmDofBka4XxZb
+wxsut+8rBSIoVKIre4Pyqfa9u1IrEnoOzMqvF16xUME2t2EaryUzAoGBANxpb4Jz
+FjH7nfPc3iejd+cXovX6x2VTJzWaknA6hGsoc+UZ01KTaKyYpq+9q9VxXhWxYsh3
+TL1JWuIBy6ao5tdt4nPBu07J7tfu5bfr3Imd8waNQxDEfKeFedskxORs+FIUzqBb
+3nIkQH8sx0Syv620coIdtEn1raVXc9QfRgSVAoGAWNFhLoGPYgsTcnrk0N1QLmnZ
+mv6kcHc3mEZhZtgi07qv7TCooYi/lPhwNbzzXQrYfbAbaU3gDy0K24z+YeNbWCjI
+XfBLUJFPHZ2G1e5vv3EG5GkoFPiLAglRmQbumG2LkmcCuEyBqlSinLslRd/997Bx
+YMoE+EfwH/9ktGhD0oMCgYEAxaSqAFDQ00ssjTM95k94Qjn4wBf7WwmgfDm6HHbs
+rOZeXk61JzPVxgcwWSB8iG4bDtq8mMQZhRbVLxqrEiwcq4r2aBSNsI305Z5sUWtn
+m+ONvA9J1yxKFzHiXjbvc2GfnoLX8gXPR4zoZOGzYg/jP5EyqSiXtUZfSodL7yeH
+8q0CgYEA2OzA59AITJe8jhC5JsVbLs7Rj4kFTjD+iZ8P86FnWBf1iDeuywEZJqvG
+n6SNK4KczDJ//DBV06w4L6iwe5iOCdf06+V7Hnkbvrjk0ONnXX7VXNgJ3/e7aJTx
+gE42Ug0qu6lXtEfYqlhQoF2lAtnYq0fty/XWMVfpjVuh1lyd4C4=
+-----END RSA PRIVATE KEY-----
\ No newline at end of file
diff --git a/src/twisted/test/server.pem b/src/twisted/test/server.pem
index 0c633e6e9e3..6d2be8be95b 100644
--- a/src/twisted/test/server.pem
+++ b/src/twisted/test/server.pem
@@ -1,97 +1,123 @@
# coding: utf-8
-from inspect import getsource
-from datetime import datetime
-from OpenSSL.crypto import FILETYPE_PEM, TYPE_RSA, X509, PKey, dump_privatekey, dump_certificate
+from datetime import datetime, timedelta
+from inspect import getsource
-key = PKey()
-key.generate_key(TYPE_RSA, 2048)
+from cryptography.hazmat.primitives.asymmetric.rsa import generate_private_key
+from cryptography.hazmat.primitives.hashes import SHA256
+from cryptography.hazmat.primitives.serialization import (
+ Encoding,
+ NoEncryption,
+ PrivateFormat,
+)
+from cryptography.x509 import (
+ CertificateBuilder,
+ Name,
+ NameAttribute,
+ NameOID,
+ SubjectAlternativeName,
+ DNSName,
+ random_serial_number,
+)
-cert = X509()
-issuer = cert.get_issuer()
-subject = cert.get_subject()
+pk = generate_private_key(key_size=2048, public_exponent=65537)
-for dn in [issuer, subject]:
- dn.C = b"TR"
- dn.ST = "Çorum".encode("utf-8")
- dn.L = "Başmakçı".encode("utf-8")
- dn.CN = b"localhost"
- dn.O = b"Twisted Matrix Labs"
- dn.OU = b"Automated Testing Authority"
- dn.emailAddress = b"security@twistedmatrix.com"
+me = Name(
+ [
+ NameAttribute(NameOID.COMMON_NAME, "A Host, Locally"),
+ NameAttribute(NameOID.COUNTRY_NAME, "TR"),
+ NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Çorum"),
+ NameAttribute(NameOID.LOCALITY_NAME, "Başmakçı"),
+ NameAttribute(NameOID.ORGANIZATION_NAME, "Twisted Matrix Labs"),
+ NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "Automated Testing Authority"),
+ NameAttribute(NameOID.EMAIL_ADDRESS, "security@twistedmatrix.com"),
+ ]
+)
-cert.set_serial_number(datetime.now().toordinal())
-cert.gmtime_adj_notBefore(0)
-cert.gmtime_adj_notAfter(60 * 60 * 24 * 365 * 100)
+certificate_bytes = (
+ CertificateBuilder()
+ .serial_number(random_serial_number())
+ .not_valid_before(datetime.now())
+ .not_valid_after(datetime.now() + timedelta(seconds=60 * 60 * 24 * 365 * 100))
+ .subject_name(me)
+ .add_extension(SubjectAlternativeName([DNSName("localhost")]), False)
+ .issuer_name(me)
+ .public_key(pk.public_key())
+ .sign(pk, algorithm=SHA256())
+).public_bytes(Encoding.PEM)
-cert.set_pubkey(key)
-cert.sign(key, "sha256")
+privkey_bytes = pk.private_bytes(
+ Encoding.PEM, PrivateFormat.TraditionalOpenSSL, NoEncryption()
+)
import __main__
+
source = getsource(__main__)
source = source.split("\n" + "-" * 5)[0].rsplit("\n", 1)[0]
with open("server.pem", "w") as fObj:
fObj.write(source)
fObj.write("\n")
- fObj.write("'''\n")
- fObj.write(dump_privatekey(FILETYPE_PEM, key).decode("ascii"))
- fObj.write(dump_certificate(FILETYPE_PEM, cert).decode("ascii"))
- fObj.write("'''\n")
+ fObj.write('"""\n')
+ fObj.write(privkey_bytes.decode("ascii"))
+ fObj.write(certificate_bytes.decode("ascii"))
+ fObj.write('"""\n')
with open(b"key.pem.no_trailing_newline", "w") as fObj:
- fObj.write(dump_privatekey(FILETYPE_PEM, key).decode("ascii").rstrip('\n'))
+ fObj.write(privkey_bytes.decode("ascii").rstrip("\n"))
with open(b"cert.pem.no_trailing_newline", "w") as fObj:
- fObj.write(dump_certificate(FILETYPE_PEM, cert).decode("ascii").rstrip('\n'))
-'''
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9Gk1skmQfONi+
-GdM2Rwb6a/2weSX7eM3MwT3vXYr+0dx9ScWERILTNkLGrvfslHKdUE7hBDKjtuj6
-KtAIrVjeDDMD6Ue77EcbL3QEO1QZeBjJ3hQbaB447PhE1wwgEsWndPMcDDVm93sO
-DELNrzWMLhabgCJ5cJYo5RQs7IvVtE36KaoSgfC9rTP8Lva+MW5wNeHn2f0hDlUF
-8jLuo1W+eDb9CHV7vwL19DZ3w74UkQ3RnfNDnZzVhsNI4YGaSBGtOHY3ioDspGQZ
-qHHfCSTjjMwq3ddEkPd7iNu4N5KUamnH69A0JfRODC8tXjFG9/WFROhYZkUQRhXk
-gRd39Yy9AgMBAAECggEAIvGt1f7VRpm8H6DpEVIdvX/gMNCqTqZ7rTcWaVmpWj5Q
-lsxflfoNDNetjkZ95PdnmJ9i/BzI+MzPj48Cw1+5GMs7UCE3EshuOV1S/Ic0GsLB
-HeiOYaQjVZSgqiPtBy5A3Rl05T1yTtUzpZxpadXTONS5c8HBXRyLewId8NFDY9ls
-76PYRq4ui7QGOmXw7VAVzg/7RxcupuSkecE7472Ek1jtEdRdplBga/XE5/+FZhrr
-NyAdVo/1VD8zpaenWiBgfqJTVc/VRBaE0kLa777E++ruqGGz/c5cQPOWzEp0vPbi
-kXz16X2TQDeTe6QfBBYjzD2+LyJh2TXfRtEn56MtJwKBgQDaTzHFOoiPS0+JpOBH
-yW2gIFigEH70Hi++m0okmewGLTGrjOsIVWx8u5QFMANEYXeXIT7sM1eyONYjtxNC
-gpeLyyN9zTyLPWdx3CzNodY2Dg/irTZtPQp7/efAHcn7kW8V0OxCGTyXAzdhKXmN
-thN9KMk6peQMU8L4FqypNznFrwKBgQDdwD0NBxqNk3/Q/qih2EJUOO7uuPAZnTJf
-neRnY4Pc94ticdQbd03ZArP3ybl9wWy+Ri9D+I9P753Hyfb7BSKwwIyYRgxSjGU/
-wqcmv0V/mSY7N4eCDaXqEjdovaZ76d3L60FPH5rJbn7yHZBYWaSqXgk0HDYUmQwg
-huPLNu8bUwKBgQCH/rGohbAwY9/mhRlaXva1u7C59czAUlW3zZFAf8pyhpDcp2p6
-xIxSn5+0I5bFcFpJgWJrTgihc5qioReUZTn20dMIOWQv8U6RtXELoHeLMPNgaDrx
-jgcL+r32BhifaJfk5UNoYcRG5rAHDQk16Gj3nQLOUC1iKIPafHWO7GJG7QKBgQCj
-yVfOhY6xP17K6S14zRjAyISCQorlAFyyjxai3rgIv7Zt8hFucAJJ5Vs0DAU7w2Ak
-cgZ7N93ydtOdO6l24uYqky3FUwfK+PPX0lhPoDse8elxF6S5BIeliervLBUJtUUj
-VxIX9QoI+do9zmRNPXkIdQhrOuMe96Qjaj5aXKrjDQKBgBS2LGghCFgqaxtHeIpl
-RLOnpxLaiitGH412O6VKHkkXaNYEOlbtFVlPuE1zHeyIvLQb666lW/w0+HMmfMTU
-SQI2gIndUb6pMzLjZUrCyYz618EoAmhx6+VnbRSY+iSEIdYqx6VBl0HY9RWJa18H
-4LPzH6dfRnKf2jCer3DtWALD
------END PRIVATE KEY-----
+ fObj.write(certificate_bytes.decode("ascii").rstrip("\n"))
+
+"""
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA0rT5+hF+1BjE7qXms9PZWHskXZGXLPiYVmiYjsVeJAOtHAYq
+8igzA49KgR1xR9M4jQ6U46nwPsnGCh4liyxdWkBLw9maxMoE+r6dW1zZ8Tllunbd
+b/Da6L8P55SKb7QGet4CB1fZ2SqZD4GvTby6xpoR09AqrfjuEIYR8V/y+8dG3mR5
+W0HqaJ58IWihAwIQSakuc8jTadJY55t7UW6Ebj2X2WTO6Zh7gJ1dyHPMVkUHJF9J
+suj/4F4lx6hWGQzWO8Nf8Q7t364pagE3evUv/BECJLONNYLaFjLtWnsCEJDV9owC
+jaxu785KuA7OM/f3h3xVIfTBTo2AlHiQnXdyrwIDAQABAoH/Ib7aSjKDHXTaFV58
+lFBZftI6AMJQc+Ncgno99J+ndB0inFpghmfpw6gvRn5wphAt/mlXbx7IW0X1cali
+WefBC7NAbx1qrBmusnnUuc0lGn0WzcY7sLHiXWQ8J9qiUUGDyCnGKWbofN9VpCYg
+7VJMl4IVWNb9/t7fQcY3GXFEeQ4mzLo7p+gPxyeUcCLVrhVrHzw1HFTIlA51LjfI
+xQM+QVeaEWQQ4UsDdPe5iGthDd7ze2F5ciDzMkShrf7URSudS+Us6vr6gDVpKAky
+eCVyFPJXCfH4qJoa6mB6L6SFzMnN3OPp3RlYQWQ7sK/ELQfhPoyHyRvL1woUIO5C
+tK0pAoGBAPS6ZSZ26M0guZ2K/2fKMiGq0jZQLcxP3N0jWm8R8ENOnuIjhCl5aKsB
+DoV0BvPv1C2vWm+VgNArgTece9l8o5f8pcfjbT5r/k8zoqgcj9CmmDofBka4XxZb
+wxsut+8rBSIoVKIre4Pyqfa9u1IrEnoOzMqvF16xUME2t2EaryUzAoGBANxpb4Jz
+FjH7nfPc3iejd+cXovX6x2VTJzWaknA6hGsoc+UZ01KTaKyYpq+9q9VxXhWxYsh3
+TL1JWuIBy6ao5tdt4nPBu07J7tfu5bfr3Imd8waNQxDEfKeFedskxORs+FIUzqBb
+3nIkQH8sx0Syv620coIdtEn1raVXc9QfRgSVAoGAWNFhLoGPYgsTcnrk0N1QLmnZ
+mv6kcHc3mEZhZtgi07qv7TCooYi/lPhwNbzzXQrYfbAbaU3gDy0K24z+YeNbWCjI
+XfBLUJFPHZ2G1e5vv3EG5GkoFPiLAglRmQbumG2LkmcCuEyBqlSinLslRd/997Bx
+YMoE+EfwH/9ktGhD0oMCgYEAxaSqAFDQ00ssjTM95k94Qjn4wBf7WwmgfDm6HHbs
+rOZeXk61JzPVxgcwWSB8iG4bDtq8mMQZhRbVLxqrEiwcq4r2aBSNsI305Z5sUWtn
+m+ONvA9J1yxKFzHiXjbvc2GfnoLX8gXPR4zoZOGzYg/jP5EyqSiXtUZfSodL7yeH
+8q0CgYEA2OzA59AITJe8jhC5JsVbLs7Rj4kFTjD+iZ8P86FnWBf1iDeuywEZJqvG
+n6SNK4KczDJ//DBV06w4L6iwe5iOCdf06+V7Hnkbvrjk0ONnXX7VXNgJ3/e7aJTx
+gE42Ug0qu6lXtEfYqlhQoF2lAtnYq0fty/XWMVfpjVuh1lyd4C4=
+-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
-MIID6DCCAtACAwtEVjANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMCVFIxDzAN
-BgNVBAgMBsOHb3J1bTEUMBIGA1UEBwwLQmHFn21ha8OnxLExEjAQBgNVBAMMCWxv
-Y2FsaG9zdDEcMBoGA1UECgwTVHdpc3RlZCBNYXRyaXggTGFiczEkMCIGA1UECwwb
-QXV0b21hdGVkIFRlc3RpbmcgQXV0aG9yaXR5MSkwJwYJKoZIhvcNAQkBFhpzZWN1
-cml0eUB0d2lzdGVkbWF0cml4LmNvbTAgFw0yMjA4MjMyMzUyNTJaGA8yMTIyMDcz
-MDIzNTI1MlowgbcxCzAJBgNVBAYTAlRSMQ8wDQYDVQQIDAbDh29ydW0xFDASBgNV
-BAcMC0JhxZ9tYWvDp8SxMRIwEAYDVQQDDAlsb2NhbGhvc3QxHDAaBgNVBAoME1R3
+MIIEJDCCAwygAwIBAgIUKaSXgzt5gDMt9GbUzLz/A9HEyFEwDQYJKoZIhvcNAQEL
+BQAwgb0xGDAWBgNVBAMMD0EgSG9zdCwgTG9jYWxseTELMAkGA1UEBhMCVFIxDzAN
+BgNVBAgMBsOHb3J1bTEUMBIGA1UEBwwLQmHFn21ha8OnxLExHDAaBgNVBAoME1R3
aXN0ZWQgTWF0cml4IExhYnMxJDAiBgNVBAsMG0F1dG9tYXRlZCBUZXN0aW5nIEF1
dGhvcml0eTEpMCcGCSqGSIb3DQEJARYac2VjdXJpdHlAdHdpc3RlZG1hdHJpeC5j
-b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9Gk1skmQfONi+GdM2
-Rwb6a/2weSX7eM3MwT3vXYr+0dx9ScWERILTNkLGrvfslHKdUE7hBDKjtuj6KtAI
-rVjeDDMD6Ue77EcbL3QEO1QZeBjJ3hQbaB447PhE1wwgEsWndPMcDDVm93sODELN
-rzWMLhabgCJ5cJYo5RQs7IvVtE36KaoSgfC9rTP8Lva+MW5wNeHn2f0hDlUF8jLu
-o1W+eDb9CHV7vwL19DZ3w74UkQ3RnfNDnZzVhsNI4YGaSBGtOHY3ioDspGQZqHHf
-CSTjjMwq3ddEkPd7iNu4N5KUamnH69A0JfRODC8tXjFG9/WFROhYZkUQRhXkgRd3
-9Yy9AgMBAAEwDQYJKoZIhvcNAQELBQADggEBABuOxiDnfrjQjbP4ZWrDj+doK8Zk
-CUwtyM3gFVF1LBZxBCxVa6hzD2N7/1o0+KHjmiGks7SnXb6aG2nEqypciZ4xkPjt
-wVIcTWCW8ddPrfMi4/esiQFlPck1p3QSfkPiAgHAjJiDDqDtqsMKr+5AkUaHlqjR
-VV3YE27x/QyLZbV7igiTPdh1fTV7+Yl8VHpBdnMRUVTFoZaIiCe0efmqsvzBd73A
-c75aKTwu6cPQ9dH/gIEOHCvrgweED7ZcabT7h/k7DXL2zhnJTPmQSJLWjfQebJOu
-4l1p7tn35xbjqu906l4iII+YqWCAj/gNT2qdcIWQmxg/reg2tRbU7Nv3M0c=
+b20wIBcNMjMwNjE0MTM0MDI4WhgPMjEyMzA1MjExMzQwMjhaMIG9MRgwFgYDVQQD
+DA9BIEhvc3QsIExvY2FsbHkxCzAJBgNVBAYTAlRSMQ8wDQYDVQQIDAbDh29ydW0x
+FDASBgNVBAcMC0JhxZ9tYWvDp8SxMRwwGgYDVQQKDBNUd2lzdGVkIE1hdHJpeCBM
+YWJzMSQwIgYDVQQLDBtBdXRvbWF0ZWQgVGVzdGluZyBBdXRob3JpdHkxKTAnBgkq
+hkiG9w0BCQEWGnNlY3VyaXR5QHR3aXN0ZWRtYXRyaXguY29tMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0rT5+hF+1BjE7qXms9PZWHskXZGXLPiYVmiY
+jsVeJAOtHAYq8igzA49KgR1xR9M4jQ6U46nwPsnGCh4liyxdWkBLw9maxMoE+r6d
+W1zZ8Tllunbdb/Da6L8P55SKb7QGet4CB1fZ2SqZD4GvTby6xpoR09AqrfjuEIYR
+8V/y+8dG3mR5W0HqaJ58IWihAwIQSakuc8jTadJY55t7UW6Ebj2X2WTO6Zh7gJ1d
+yHPMVkUHJF9Jsuj/4F4lx6hWGQzWO8Nf8Q7t364pagE3evUv/BECJLONNYLaFjLt
+WnsCEJDV9owCjaxu785KuA7OM/f3h3xVIfTBTo2AlHiQnXdyrwIDAQABoxgwFjAU
+BgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAEHAErq/Fs8h
+M+kwGCt5Ochqyu/IzPbwgQ27n5IJehl7kmpoXBxGa/u+ajoxrZaOheg8E2MYVwQi
+FTKE9wJgaN3uGo4bzCbCYxDm7tflQORo6QOZlumfiQIzXON2RvgJpwFfkLNtq0t9
+e453kJ7+e11Wah46bc3RAvBZpwswh6hDv2FvFUZ+IUcO0tU8O4kWrLIFPpJbcHQq
+wezjky773X4CNEtoeuTb8/ws/eED/TGZ2AZO+BWT93OZJgwE2x3iUd3k8HbwxfoY
+bZ+NHgtM7iKRcL59asB0OMi3Ays0+IOfZ1+3aB82zYlxFBoDyalR7NJjJGdTwNFt
+3CPGCQ28cDk=
-----END CERTIFICATE-----
-'''
+"""
From 1f0c2a3a774d89fb10782a8abf62e219d1f4818f Mon Sep 17 00:00:00 2001
From: Glyph <code@glyph.im>
Date: Wed, 14 Jun 2023 14:06:56 -0700
Subject: [PATCH 2/4] todo server.pem should generate this too
---
src/twisted/protocols/test/test_tls.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/twisted/protocols/test/test_tls.py b/src/twisted/protocols/test/test_tls.py
index 5915d6bc5b2..37de80feb9f 100644
--- a/src/twisted/protocols/test/test_tls.py
+++ b/src/twisted/protocols/test/test_tls.py
@@ -522,9 +522,10 @@ def cbHandshook(ignored):
self.assertIsInstance(cert, crypto.X509)
self.assertEqual(
cert.digest("sha256"),
- # openssl x509 -noout -sha256 -fingerprint -in server.pem
- b"C4:F5:8E:9D:A0:AC:85:24:9B:2D:AA:2C:EC:87:DB:5F:33:22:94:"
- b"01:94:DC:D3:42:4C:E4:B9:F5:0F:45:F2:24",
+ # openssl x509 -noout -sha256 -fingerprint
+ # -in src/twisted/test/server.pem
+ b"D6:F2:2C:74:3B:E2:5E:F9:CA:DA:47:08:14:78:20:75:78:95:9E:52"
+ b":BD:D2:7C:77:DD:D4:EE:DE:33:BF:34:40",
)
handshakeDeferred.addCallback(cbHandshook)
From 137a3a6fa27374ecb879c67557197a3f0b37aab1 Mon Sep 17 00:00:00 2001
From: Glyph <code@glyph.im>
Date: Wed, 14 Jun 2023 14:08:13 -0700
Subject: [PATCH 3/4] address review
---
src/twisted/test/server.pem | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/twisted/test/server.pem b/src/twisted/test/server.pem
index 6d2be8be95b..33fdbbd1cac 100644
--- a/src/twisted/test/server.pem
+++ b/src/twisted/test/server.pem
@@ -41,7 +41,7 @@ certificate_bytes = (
.not_valid_before(datetime.now())
.not_valid_after(datetime.now() + timedelta(seconds=60 * 60 * 24 * 365 * 100))
.subject_name(me)
- .add_extension(SubjectAlternativeName([DNSName("localhost")]), False)
+ .add_extension(SubjectAlternativeName([DNSName("localhost")]), critical=False)
.issuer_name(me)
.public_key(pk.public_key())
.sign(pk, algorithm=SHA256())
From c8dce7b42b13466afd24ea5f9bbfc9a1c08c585f Mon Sep 17 00:00:00 2001
From: Glyph <code@glyph.im>
Date: Wed, 14 Jun 2023 14:17:12 -0700
Subject: [PATCH 4/4] hooray, type stubs are updated too
---
src/twisted/internet/_sslverify.py | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/twisted/internet/_sslverify.py b/src/twisted/internet/_sslverify.py
index 6824482dc5b..d8f62e40954 100644
--- a/src/twisted/internet/_sslverify.py
+++ b/src/twisted/internet/_sslverify.py
@@ -159,11 +159,8 @@ def _selectVerifyImplementation():
)
try:
- from service_identity import VerificationError # type: ignore[import]
- from service_identity.pyopenssl import ( # type: ignore[import]
- verify_hostname,
- verify_ip_address,
- )
+ from service_identity import VerificationError
+ from service_identity.pyopenssl import verify_hostname, verify_ip_address
return verify_hostname, verify_ip_address, VerificationError
except ImportError as e:

View File

@ -0,0 +1,18 @@
Index: Twisted-22.10.0/setup.cfg
===================================================================
--- Twisted-22.10.0.orig/setup.cfg
+++ Twisted-22.10.0/setup.cfg
@@ -72,10 +72,10 @@ serial =
pyserial >= 3.0
pywin32 != 226; platform_system == "Windows"
http2 =
- h2 >= 3.0, < 5.0
- priority >= 1.1.0, < 2.0
+ h2 >= 3.0
+ priority >= 1.1.0
contextvars =
- contextvars >= 2.4, < 3; python_version < "3.7"
+ contextvars >= 2.4; python_version < "3.7"
all_non_platform =
%(test)s
%(tls)s

View File

@ -0,0 +1,360 @@
From 1716d312600a9c49279e6c15da9ad8ca21431580 Mon Sep 17 00:00:00 2001
From: Glyph <code@glyph.im>
Date: Thu, 8 Jun 2023 18:13:11 -0700
Subject: [PATCH 1/2] remove PyNaCl optional dependency
---
docs/installation/howto/optional.rst | 3 -
pyproject.toml | 6 -
src/twisted/conch/newsfragments/11871.removal | 1 +
src/twisted/conch/ssh/_keys_pynacl.py | 104 ------------
src/twisted/conch/ssh/keys.py | 9 +-
src/twisted/conch/test/test_keys.py | 157 +-----------------
tox.ini | 4 +-
7 files changed, 6 insertions(+), 278 deletions(-)
create mode 100644 src/twisted/conch/newsfragments/11871.removal
delete mode 100644 src/twisted/conch/ssh/_keys_pynacl.py
Index: Twisted-22.10.0/docs/installation/howto/optional.rst
===================================================================
--- Twisted-22.10.0.orig/docs/installation/howto/optional.rst
+++ Twisted-22.10.0/docs/installation/howto/optional.rst
@@ -67,7 +67,6 @@ The following optional dependencies are
.. _service_identity: https://pypi.python.org/pypi/service_identity
.. _pyasn1: https://pypi.python.org/pypi/pyasn1
.. _cryptography: https://pypi.python.org/pypi/cryptography
-.. _PyNaCl: https://pypi.python.org/pypi/PyNaCl
.. _SOAPpy: https://pypi.python.org/pypi/SOAPpy
.. _pyserial: https://pypi.python.org/pypi/pyserial
.. _pyobjc: https://pypi.python.org/pypi/pyobjc
Index: Twisted-22.10.0/src/twisted/conch/newsfragments/11871.removal
===================================================================
--- /dev/null
+++ Twisted-22.10.0/src/twisted/conch/newsfragments/11871.removal
@@ -0,0 +1 @@
+Due to changes in the way raw private key byte serialization are handled in Cryptography, and widespread support for Ed25519 in current versions of OpenSSL, we no longer support PyNaCl as a fallback for Ed25519 keys in Conch.
Index: Twisted-22.10.0/src/twisted/conch/ssh/_keys_pynacl.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/conch/ssh/_keys_pynacl.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# -*- test-case-name: twisted.conch.test.test_keys -*-
-# Copyright (c) Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-"""
-Optional PyNaCl fallback code for Ed25519 keys.
-"""
-
-from cryptography.exceptions import InvalidSignature
-from cryptography.hazmat.primitives import serialization
-from cryptography.hazmat.primitives.asymmetric import ed25519
-from nacl.exceptions import BadSignatureError
-from nacl.signing import SigningKey, VerifyKey
-
-
-class Ed25519PublicKey(ed25519.Ed25519PublicKey):
- def __init__(self, data: bytes):
- self._key = VerifyKey(data)
-
- def __bytes__(self) -> bytes:
- return bytes(self._key)
-
- def __hash__(self) -> int:
- return hash(bytes(self))
-
- def __eq__(self, other: object) -> bool:
- if not isinstance(other, self.__class__):
- return False
- return self._key == other._key
-
- def __ne__(self, other: object) -> bool:
- return not (self == other)
-
- @classmethod
- def from_public_bytes(cls, data: bytes) -> ed25519.Ed25519PublicKey:
- return cls(data)
-
- def public_bytes(
- self,
- encoding: serialization.Encoding,
- format: serialization.PublicFormat,
- ) -> bytes:
- if (
- encoding is not serialization.Encoding.Raw
- or format is not serialization.PublicFormat.Raw
- ):
- raise ValueError("Both encoding and format must be Raw")
- return bytes(self)
-
- def verify(self, signature: bytes, data: bytes) -> None:
- try:
- self._key.verify(data, signature)
- except BadSignatureError as e:
- raise InvalidSignature(str(e))
-
-
-class Ed25519PrivateKey(ed25519.Ed25519PrivateKey):
- def __init__(self, data: bytes):
- self._key = SigningKey(data)
-
- def __bytes__(self) -> bytes:
- return bytes(self._key)
-
- def __hash__(self) -> int:
- return hash(bytes(self))
-
- def __eq__(self, other: object) -> bool:
- if not isinstance(other, self.__class__):
- return False
- return self._key == other._key
-
- def __ne__(self, other: object) -> bool:
- return not (self == other)
-
- @classmethod
- def generate(cls) -> ed25519.Ed25519PrivateKey:
- return cls(bytes(SigningKey.generate()))
-
- @classmethod
- def from_private_bytes(cls, data: bytes) -> ed25519.Ed25519PrivateKey:
- return cls(data)
-
- def public_key(self) -> ed25519.Ed25519PublicKey:
- return Ed25519PublicKey(bytes(self._key.verify_key))
-
- def private_bytes(
- self,
- encoding: serialization.Encoding,
- format: serialization.PrivateFormat,
- encryption_algorithm: serialization.KeySerializationEncryption,
- ) -> bytes:
- if (
- encoding is not serialization.Encoding.Raw
- or format is not serialization.PrivateFormat.Raw
- or not isinstance(encryption_algorithm, serialization.NoEncryption)
- ):
- raise ValueError(
- "Encoding and format must be Raw and "
- "encryption_algorithm must be NoEncryption"
- )
- return bytes(self)
-
- def sign(self, data: bytes) -> bytes:
- return self._key.sign(data).signature
Index: Twisted-22.10.0/src/twisted/conch/ssh/keys.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/conch/ssh/keys.py
+++ Twisted-22.10.0/src/twisted/conch/ssh/keys.py
@@ -14,7 +14,6 @@ import unicodedata
import warnings
from base64 import b64encode, decodebytes, encodebytes
from hashlib import md5, sha256
-from typing import Optional, Type
import bcrypt
from cryptography import utils
@@ -68,18 +67,8 @@ _secToNist = {
}
-Ed25519PublicKey: Optional[Type[ed25519.Ed25519PublicKey]]
-Ed25519PrivateKey: Optional[Type[ed25519.Ed25519PrivateKey]]
-
-if default_backend().ed25519_supported():
- Ed25519PublicKey = ed25519.Ed25519PublicKey
- Ed25519PrivateKey = ed25519.Ed25519PrivateKey
-else: # pragma: no cover
- try:
- from twisted.conch.ssh._keys_pynacl import Ed25519PrivateKey, Ed25519PublicKey
- except ImportError:
- Ed25519PublicKey = None
- Ed25519PrivateKey = None
+Ed25519PublicKey = ed25519.Ed25519PublicKey
+Ed25519PrivateKey = ed25519.Ed25519PrivateKey
class BadKeyError(Exception):
Index: Twisted-22.10.0/src/twisted/conch/test/test_keys.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/conch/test/test_keys.py
+++ Twisted-22.10.0/src/twisted/conch/test/test_keys.py
@@ -22,20 +22,15 @@ if cryptography is None:
skipCryptography = "Cannot run without cryptography."
pyasn1 = requireModule("pyasn1")
-_keys_pynacl = requireModule("twisted.conch.ssh._keys_pynacl")
-
if cryptography and pyasn1:
- from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from twisted.conch.ssh import common, keys, sexpy
- ED25519_SUPPORTED = (
- default_backend().ed25519_supported() or _keys_pynacl is not None
- )
+ ED25519_SUPPORTED = default_backend().ed25519_supported()
else:
ED25519_SUPPORTED = False
@@ -1676,156 +1671,6 @@ attr n:
)
-class PyNaClKeyTests(KeyTests):
- """
- Key tests, but forcing the use of C{PyNaCl}.
- """
-
- if cryptography is None:
- skip = skipCryptography
- if _keys_pynacl is None:
- skip = "Cannot run without PyNaCl"
-
- def setUp(self):
- super().setUp()
- self.patch(keys, "Ed25519PublicKey", _keys_pynacl.Ed25519PublicKey)
- self.patch(keys, "Ed25519PrivateKey", _keys_pynacl.Ed25519PrivateKey)
-
- def test_naclPrivateBytes(self):
- """
- L{_keys_pynacl.Ed25519PrivateKey.private_bytes} and
- L{_keys_pynacl.Ed25519PrivateKey.from_private_bytes} round-trip.
- """
- from cryptography.hazmat.primitives import serialization
-
- key = _keys_pynacl.Ed25519PrivateKey.generate()
- key_bytes = key.private_bytes(
- serialization.Encoding.Raw,
- serialization.PrivateFormat.Raw,
- serialization.NoEncryption(),
- )
- self.assertIsInstance(key_bytes, bytes)
- self.assertEqual(
- key, _keys_pynacl.Ed25519PrivateKey.from_private_bytes(key_bytes)
- )
-
- def test_naclPrivateBytesInvalidParameters(self):
- """
- L{_keys_pynacl.Ed25519PrivateKey.private_bytes} only accepts certain parameters.
- """
- from cryptography.hazmat.primitives import serialization
-
- key = _keys_pynacl.Ed25519PrivateKey.generate()
- self.assertRaises(
- ValueError,
- key.private_bytes,
- serialization.Encoding.PEM,
- serialization.PrivateFormat.Raw,
- serialization.NoEncryption(),
- )
- self.assertRaises(
- ValueError,
- key.private_bytes,
- serialization.Encoding.Raw,
- serialization.PrivateFormat.PKCS8,
- serialization.NoEncryption(),
- )
- self.assertRaises(
- ValueError,
- key.private_bytes,
- serialization.Encoding.Raw,
- serialization.PrivateFormat.Raw,
- serialization.BestAvailableEncryption(b"password"),
- )
-
- def test_naclPrivateHash(self):
- """
- L{_keys_pynacl.Ed25519PrivateKey.__hash__} allows instances to be hashed.
- """
- key = _keys_pynacl.Ed25519PrivateKey.generate()
- d = {key: True}
- self.assertTrue(d[key])
-
- def test_naclPrivateEquality(self):
- """
- L{_keys_pynacl.Ed25519PrivateKey} implements equality test methods.
- """
- key1 = _keys_pynacl.Ed25519PrivateKey.generate()
- key2 = _keys_pynacl.Ed25519PrivateKey.generate()
- self.assertEqual(key1, key1)
- self.assertNotEqual(key1, key2)
- self.assertNotEqual(key1, bytes(key1))
-
- def test_naclPublicBytes(self):
- """
- L{_keys_pynacl.Ed25519PublicKey.public_bytes} and
- L{_keys_pynacl.Ed25519PublicKey.from_public_bytes} round-trip.
- """
- from cryptography.hazmat.primitives import serialization
-
- key = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
- key_bytes = key.public_bytes(
- serialization.Encoding.Raw, serialization.PublicFormat.Raw
- )
- self.assertIsInstance(key_bytes, bytes)
- self.assertEqual(
- key, _keys_pynacl.Ed25519PublicKey.from_public_bytes(key_bytes)
- )
-
- def test_naclPublicBytesInvalidParameters(self):
- """
- L{_keys_pynacl.Ed25519PublicKey.public_bytes} only accepts certain parameters.
- """
- from cryptography.hazmat.primitives import serialization
-
- key = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
- self.assertRaises(
- ValueError,
- key.public_bytes,
- serialization.Encoding.PEM,
- serialization.PublicFormat.Raw,
- )
- self.assertRaises(
- ValueError,
- key.public_bytes,
- serialization.Encoding.Raw,
- serialization.PublicFormat.PKCS1,
- )
-
- def test_naclPublicHash(self):
- """
- L{_keys_pynacl.Ed25519PublicKey.__hash__} allows instances to be hashed.
- """
- key = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
- d = {key: True}
- self.assertTrue(d[key])
-
- def test_naclPublicEquality(self):
- """
- L{_keys_pynacl.Ed25519PublicKey} implements equality test methods.
- """
- key1 = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
- key2 = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
- self.assertEqual(key1, key1)
- self.assertNotEqual(key1, key2)
- self.assertNotEqual(key1, bytes(key1))
-
- def test_naclVerify(self):
- """
- L{_keys_pynacl.Ed25519PublicKey.verify} raises appropriate exceptions.
- """
- key = _keys_pynacl.Ed25519PrivateKey.generate()
- self.assertIsInstance(key, keys.Ed25519PrivateKey)
- signature = key.sign(b"test data")
- self.assertIsNone(key.public_key().verify(signature, b"test data"))
- self.assertRaises(
- InvalidSignature, key.public_key().verify, signature, b"wrong data"
- )
- self.assertRaises(
- InvalidSignature, key.public_key().verify, b"0" * 64, b"test data"
- )
-
-
class PersistentRSAKeyTests(unittest.TestCase):
"""
Tests for L{keys._getPersistentRSAKey}.

25
skip_MultiCast.patch Normal file
View File

@ -0,0 +1,25 @@
---
src/twisted/test/test_udp.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: Twisted-22.10.0/src/twisted/test/test_udp.py
===================================================================
--- Twisted-22.10.0.orig/src/twisted/test/test_udp.py
+++ Twisted-22.10.0/src/twisted/test/test_udp.py
@@ -8,7 +8,7 @@ Tests for implementations of L{IReactorU
import os
-from unittest import skipIf
+from unittest import skipIf, SkipTest
from twisted.internet import defer, error, interfaces, protocol, reactor, udp
from twisted.internet.defer import Deferred, gatherResults, maybeDeferred
@@ -581,6 +581,7 @@ class MulticastTests(TestCase):
skip = "This reactor does not support multicast"
def setUp(self):
+ raise SkipTest("Multicast networking doesn't work with OBS")
self.server = Server()
self.client = Client()
# multicast won't work if we listen over loopback, apparently

116
support-new-glibc.patch Normal file
View File

@ -0,0 +1,116 @@
From da3bf3dc29f067e7019b2a1c205834ab64b2139a Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri, 9 Dec 2022 10:16:42 -0800
Subject: [PATCH] #11786 fix misuse of mktime in tests
---
src/twisted/logger/test/test_format.py | 27 +++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/src/twisted/logger/test/test_format.py b/src/twisted/logger/test/test_format.py
index dbfbe1af1ae..0671b6662c8 100644
--- a/src/twisted/logger/test/test_format.py
+++ b/src/twisted/logger/test/test_format.py
@@ -166,16 +166,17 @@ def test_formatTimeWithDefaultFormat(self) -> None:
def testForTimeZone(name: str, expectedDST: str, expectedSTD: str) -> None:
setTZ(name)
- localDST = mktime((2006, 6, 30, 0, 0, 0, 4, 181, 1))
localSTD = mktime((2007, 1, 31, 0, 0, 0, 2, 31, 0))
-
- self.assertEqual(formatTime(localDST), expectedDST)
self.assertEqual(formatTime(localSTD), expectedSTD)
+ if expectedDST:
+ localDST = mktime((2006, 6, 30, 0, 0, 0, 4, 181, 1))
+ self.assertEqual(formatTime(localDST), expectedDST)
+
# UTC
testForTimeZone(
"UTC+00",
- "2006-06-30T00:00:00+0000",
+ None,
"2007-01-31T00:00:00+0000",
)
@@ -196,7 +197,7 @@ def testForTimeZone(name: str, expectedDST: str, expectedSTD: str) -> None:
# No DST
testForTimeZone(
"CST+06",
- "2006-06-30T00:00:00-0600",
+ None,
"2007-01-31T00:00:00-0600",
)
@@ -211,7 +212,7 @@ def test_formatTimeWithNoFormat(self) -> None:
"""
If C{timeFormat} argument is L{None}, we get the default output.
"""
- t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, 1))
+ t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, -1))
self.assertEqual(formatTime(t, timeFormat=None), "-")
self.assertEqual(formatTime(t, timeFormat=None, default="!"), "!")
@@ -219,7 +220,7 @@ def test_formatTimeWithAlternateTimeFormat(self) -> None:
"""
Alternate time format in output.
"""
- t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, 1))
+ t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, -1))
self.assertEqual(formatTime(t, timeFormat="%Y/%W"), "2013/38")
def test_formatTimePercentF(self) -> None:
@@ -246,7 +247,7 @@ def test_formatTimeDefault(self) -> None:
addTZCleanup(self)
setTZ("UTC+00")
- t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, 1))
+ t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, -1))
event = dict(log_format="XYZZY", log_time=t)
self.assertEqual(
formatEventAsClassicLogText(event),
@@ -539,7 +540,7 @@ def test_eventAsTextSystemOnly(self) -> None:
except CapturedError:
f = Failure()
- t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, 1))
+ t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, -1))
event: LogEvent = {
"log_format": "ABCD",
"log_system": "fake_system",
@@ -573,7 +574,7 @@ def test_eventAsTextTimestampOnly(self) -> None:
except CapturedError:
f = Failure()
- t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, 1))
+ t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, -1))
event: LogEvent = {
"log_format": "ABCD",
"log_system": "fake_system",
@@ -601,7 +602,7 @@ def test_eventAsTextSystemMissing(self) -> None:
except CapturedError:
f = Failure()
- t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, 1))
+ t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, -1))
event: LogEvent = {
"log_format": "ABCD",
"log_time": t,
@@ -628,7 +629,7 @@ def test_eventAsTextSystemMissingNamespaceAndLevel(self) -> None:
except CapturedError:
f = Failure()
- t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, 1))
+ t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, -1))
event: LogEvent = {
"log_format": "ABCD",
"log_time": t,
@@ -657,7 +658,7 @@ def test_eventAsTextSystemMissingLevelOnly(self) -> None:
except CapturedError:
f = Failure()
- t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, 1))
+ t = mktime((2013, 9, 24, 11, 40, 47, 1, 267, -1))
event: LogEvent = {
"log_format": "ABCD",
"log_time": t,