Hello community,

here is the log from the commit of package python-TxSNI for openSUSE:Factory 
checked in at 2020-04-18 00:32:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-TxSNI (Old)
 and      /work/SRC/openSUSE:Factory/.python-TxSNI.new.2738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-TxSNI"

Sat Apr 18 00:32:00 2020 rev:3 rq:794853 version:0.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-TxSNI/python-TxSNI.changes        
2019-06-13 23:01:32.823509924 +0200
+++ /work/SRC/openSUSE:Factory/.python-TxSNI.new.2738/python-TxSNI.changes      
2020-04-18 00:33:21.490416063 +0200
@@ -1,0 +2,9 @@
+Fri Apr 17 09:38:39 UTC 2020 - Marketa Calabkova <mcalabk...@suse.com>
+
+- Update to 0.20.0
+  * Support new OpenSSL
+  * Test ALPN and NPN separately.
+  * Switch cert_builder from print to twisted.logger. 
+- Drop unneeded openssl111.patch
+
+-------------------------------------------------------------------

Old:
----
  openssl111.patch
  python-TxSNI-0.1.9.tar.gz

New:
----
  python-TxSNI-0.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-TxSNI.spec ++++++
--- /var/tmp/diff_new_pack.bxa2Kl/_old  2020-04-18 00:33:22.178417488 +0200
+++ /var/tmp/diff_new_pack.bxa2Kl/_new  2020-04-18 00:33:22.182417497 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-TxSNI
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,14 +18,13 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-TxSNI
-Version:        0.1.9
+Version:        0.2.0
 Release:        0
 Summary:        Python module for running a TLS server with Twisted
 License:        MIT
 Group:          Development/Languages/Python
 URL:            https://github.com/glyph/txsni
 Source0:        
https://github.com/glyph/txsni/archive/v%{version}/%{name}-%{version}.tar.gz
-Patch0:         openssl111.patch
 BuildRequires:  %{python_module Twisted} >= 14.0.0
 BuildRequires:  %{python_module pyOpenSSL} >= 0.14
 BuildRequires:  fdupes
@@ -40,7 +39,6 @@
 
 %prep
 %setup -q -n txsni-%{version}
-%patch0 -p1
 
 %build
 %python_build

++++++ python-TxSNI-0.1.9.tar.gz -> python-TxSNI-0.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/.travis/install.sh 
new/txsni-0.2.0/.travis/install.sh
--- old/txsni-0.1.9/.travis/install.sh  2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/.travis/install.sh  1970-01-01 01:00:00.000000000 +0100
@@ -1,34 +0,0 @@
-#!/bin/bash
-
-set -e
-set -x
-
-# Upgrade packaging tools separately, so that other installations are
-# performed with the upgraded tools.
-pip install -U pip setuptools wheel
-pip install tox codecov
-
-if [ "${TOXENV::5}" == "pypy-" ]; then
-    git clone --depth 1 https://github.com/yyuu/pyenv.git ~/.pyenv
-    PYENV_ROOT="$HOME/.pyenv"
-    PATH="$PYENV_ROOT/bin:$PATH"
-    eval "$(pyenv init -)"
-    pyenv install pypy-4.0.1
-    pyenv global pypy-4.0.1
-fi
-
-if [[ -v OPENSSL_VERSION ]]; then
-    OPENSSL_DIR="${HOME}/ossl"
-    mkdir -p "${OPENSSL_DIR}"
-    curl -O https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz
-    tar zxf openssl-$OPENSSL_VERSION.tar.gz
-    cd openssl-$OPENSSL_VERSION
-    ./config shared no-asm no-ssl2 -fPIC --prefix="${OPENSSL_DIR}"
-    # modify the shlib version to a unique one to make sure the dynamic
-    # linker doesn't load the system one.
-    sed -i "s/^SHLIB_MAJOR=.*/SHLIB_MAJOR=100/" Makefile
-    sed -i "s/^SHLIB_MINOR=.*/SHLIB_MINOR=0.0/" Makefile
-    sed -i "s/^SHLIB_VERSION_NUMBER=.*/SHLIB_VERSION_NUMBER=100.0.0/" Makefile
-    make depend
-    make install
-fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/.travis/run.sh 
new/txsni-0.2.0/.travis/run.sh
--- old/txsni-0.1.9/.travis/run.sh      2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/.travis/run.sh      1970-01-01 01:00:00.000000000 +0100
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-set -e
-set -x
-
-if [ "${TOXENV::5}" == "pypy-" ]; then
-    PYENV_ROOT="$HOME/.pyenv"
-    PATH="$PYENV_ROOT/bin:$PATH"
-    eval "$(pyenv init -)"
-fi
-
-if [[ -v OPENSSL_VERSION ]]; then
-    OPENSSL_DIR="${HOME}/ossl"
-
-    export PATH="$HOME/$OPENSSL_DIR/bin:$PATH"
-    export CFLAGS="-I$HOME/$OPENSSL_DIR/include"
-    # rpath on linux will cause it to use an absolute path so we don't need to 
do LD_LIBRARY_PATH
-    export LDFLAGS="-L$HOME/$OPENSSL_DIR/lib -Wl,-rpath=$HOME/$OPENSSL_DIR/lib"
-fi
-
-tox
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/.travis.yml new/txsni-0.2.0/.travis.yml
--- old/txsni-0.1.9/.travis.yml 2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/.travis.yml 2020-04-06 08:15:02.000000000 +0200
@@ -4,29 +4,23 @@
 branches:
   only:
     - master
-python:
-  - 2.7
 
-env:
-  - TOXENV=py27-twlatest OPENSSL_VERSION=1.0.2h
-  - TOXENV=py27-twlatest
-  - TOXENV=py36-twlatest
-  - TOXENV=pypy-twlatest OPENSSL_VERSION=1.0.2h
-  - TOXENV=pypy-twlatest
-  - TOXENV=py27-tw14 OPENSSL_VERSION=1.0.2h
-  - TOXENV=py27-tw14
-  - TOXENV=pypy-tw14 OPENSSL_VERSION=1.0.2h
-  - TOXENV=pypy-tw14
-  - TOXENV=py27-twtrunk OPENSSL_VERSION=1.0.2h
-  - TOXENV=py27-twtrunk
-  - TOXENV=pypy-twtrunk OPENSSL_VERSION=1.0.2h
-  - TOXENV=pypy-twtrunk
-
-install:
-  - "./.travis/install.sh"
+matrix:
+  include:
+    - env: TOXENV=py27-twlatest
+      python: 2.7
+    - env: TOXENV=py36-twlatest
+      python: 3.6
+    - env: TOXENV=py36-twtrunk
+      python: 3.6
+    - env: TOXENV=pypy3-twlatest
+      python: "pypy3"
+    - env: TOXENV=pypy3-twtrunk
+      python: "pypy3"
 
 script:
-  - "./.travis/run.sh"
+  - pip install tox codecov
+  - tox
 
 after_success:
   # Codecov needs combined coverage, and having the raw report in the test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/README.rst new/txsni-0.2.0/README.rst
--- old/txsni-0.1.9/README.rst  2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/README.rst  2020-04-06 08:15:02.000000000 +0200
@@ -15,7 +15,7 @@
    $ cat public-stuff/mydomain.crt.pem >> certificates/mydomain.example.com.pem
    $ cat public-stuff/my-certificate-authority-chain.crt.pem >> \
        certificates/mydomain.example.com.pem
-   $ twistd -n web --port txsni:certificates:tcp:443
+   $ twist web --port txsni:certificates:tcp:443
 
 Enjoy!
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/setup.py new/txsni-0.2.0/setup.py
--- old/txsni-0.1.9/setup.py    2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/setup.py    2020-04-06 08:15:02.000000000 +0200
@@ -21,7 +21,7 @@
         "Twisted[tls]>=14.0",
         "pyOpenSSL>=0.14",
     ],
-    version="0.1.9",
+    version="0.2.0",
     long_description=long_description,
     license="MIT",
     url="https://github.com/glyph/txsni";,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/tox.ini new/txsni-0.2.0/tox.ini
--- old/txsni-0.1.9/tox.ini     2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/tox.ini     2020-04-06 08:15:02.000000000 +0200
@@ -1,12 +1,14 @@
 [tox]
-envlist = 
coverage-clean,{py27,pypy,py34,py35,py36}-{twtrunk,twlatest,tw14},coverage-report
+envlist = 
coverage-clean,py27-twlatest,{pypy3,py36}-{twtrunk,twlatest},coverage-report
 
 [testenv:coverage-clean]
+depends =
 deps = coverage
 skip_install = true
 commands = coverage erase
 
 [testenv:coverage-report]
+depends = {py27,pypy3,py36}-{twtrunk,twlatest}
 deps = coverage
 skip_install = true
 commands =
@@ -14,12 +16,12 @@
     coverage report
 
 [testenv]
+depends = coverage-clean
 whitelist_externals =
     mkdir
 deps =
     twlatest: Twisted[tls]
     twtrunk: 
https://github.com/twisted/twisted/archive/trunk.zip#egg=Twisted[tls]
-    tw132: Twisted[tls]==14.0
     coverage
     cryptography
 commands =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/txsni/maputils.py 
new/txsni-0.2.0/txsni/maputils.py
--- old/txsni-0.1.9/txsni/maputils.py   2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/txsni/maputils.py   1970-01-01 01:00:00.000000000 +0100
@@ -1,18 +0,0 @@
-
-
-class Cache(object):
-
-    def __init__(self, mapping):
-        self.mapping = mapping
-        self.cache = {}
-
-
-    def __getitem__(self, key):
-        if key in self.cache:
-            return self.cache[key]
-        else:
-            value = self.mapping[key]
-            self.cache[key] = value
-            return value
-
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/txsni-0.1.9/txsni/only_noticed_pypi_pem_after_i_wrote_this.py 
new/txsni-0.2.0/txsni/only_noticed_pypi_pem_after_i_wrote_this.py
--- old/txsni-0.1.9/txsni/only_noticed_pypi_pem_after_i_wrote_this.py   
2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/txsni/only_noticed_pypi_pem_after_i_wrote_this.py   
2020-04-06 08:15:02.000000000 +0200
@@ -12,6 +12,7 @@
     """
     certificates = []
     keys = []
+    blobs = [b""]
     for line in pemdata.split(b"\n"):
         if line.startswith(b'-----BEGIN'):
             if b'CERTIFICATE' in line:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/txsni/parser.py 
new/txsni-0.2.0/txsni/parser.py
--- old/txsni-0.1.9/txsni/parser.py     2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/txsni/parser.py     2020-04-06 08:15:02.000000000 +0200
@@ -8,7 +8,6 @@
 from twisted.plugin import IPlugin
 
 from txsni.snimap import SNIMap
-from txsni.maputils import Cache
 from txsni.snimap import HostDirectoryMap
 from twisted.python.filepath import FilePath
 from txsni.tlsendpoint import TLSEndpoint
@@ -23,9 +22,7 @@
             return ':'.join([item.replace(':', '\\:') for item in items])
         sub = colonJoin(list(args) + ['='.join(item) for item in kw.items()])
         subEndpoint = serverFromString(reactor, sub)
-        contextFactory = SNIMap(
-            Cache(HostDirectoryMap(FilePath(expanduser(pemdir))))
-        )
+        contextFactory = SNIMap(HostDirectoryMap(FilePath(expanduser(pemdir))))
         return TLSEndpoint(endpoint=subEndpoint,
                            contextFactory=contextFactory)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/txsni/snimap.py 
new/txsni-0.2.0/txsni/snimap.py
--- old/txsni-0.1.9/txsni/snimap.py     2017-05-25 04:03:50.000000000 +0200
+++ new/txsni-0.2.0/txsni/snimap.py     2020-04-06 08:15:02.000000000 +0200
@@ -5,7 +5,7 @@
 from OpenSSL.SSL import Connection
 
 from twisted.internet.interfaces import IOpenSSLServerConnectionCreator
-from twisted.internet.ssl import CertificateOptions, ContextFactory
+from twisted.internet.ssl import CertificateOptions
 
 from txsni.only_noticed_pypi_pem_after_i_wrote_this import (
     certificateOptionsFromPileOfPEM
@@ -67,8 +67,8 @@
     def __setattr__(self, attr, val):
         if attr in ('_obj', '_factory'):
             self.__dict__[attr] = val
-
-        return setattr(self._obj, attr, val)
+        else:
+            setattr(self._obj, attr, val)
 
     def __delattr__(self, attr):
         return delattr(self._obj, attr)
@@ -106,8 +106,8 @@
     def __setattr__(self, attr, val):
         if attr in ('_obj', '_factory'):
             self.__dict__[attr] = val
-
-        return setattr(self._obj, attr, val)
+        else:
+            return setattr(self._obj, attr, val)
 
     def __delattr__(self, attr):
         return delattr(self._obj, attr)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/txsni/test/certs/cert_builder.py 
new/txsni-0.2.0/txsni/test/certs/cert_builder.py
--- old/txsni-0.1.9/txsni/test/certs/cert_builder.py    2017-05-25 
04:03:50.000000000 +0200
+++ new/txsni-0.2.0/txsni/test/certs/cert_builder.py    2020-04-06 
08:15:02.000000000 +0200
@@ -1,10 +1,13 @@
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 from cryptography import x509
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives import hashes, serialization
 from cryptography.hazmat.primitives.asymmetric import rsa
 from cryptography.x509.oid import NameOID
+
+from twisted.logger import Logger
+
 import datetime
 import uuid
 import os
@@ -35,6 +38,8 @@
 ]
 
 
+_LOGGER = Logger()
+
 def _build_root_cert():
     """
     Builds a single root certificate that can be used to sign the others. This
@@ -43,7 +48,7 @@
     build the leaves.
     """
     if os.path.isfile(ROOT_CERT_PATH) and os.path.isfile(ROOT_KEY_PATH):
-        print("Root already exists, not regenerating.")
+        _LOGGER.info("Root already exists, not regenerating.")
         with open(ROOT_CERT_PATH, 'rb') as f:
             certificate = x509.load_pem_x509_certificate(
                 f.read(), default_backend()
@@ -99,7 +104,7 @@
             certificate.public_bytes(serialization.Encoding.PEM)
         )
 
-    print("Built root certificate.")
+    _LOGGER.info("Built root certificate.")
 
     return certificate, private_key
 
@@ -109,7 +114,8 @@
     Builds a single leaf certificate, signed by the CA's private key.
     """
     if os.path.isfile(certfile):
-        print("%s already exists, not regenerating" % hostname)
+        _LOGGER.info("{hostname} already exists, not regenerating",
+                     hostname=hostname)
         return
 
     private_key = rsa.generate_private_key(
@@ -158,7 +164,7 @@
             certificate.public_bytes(serialization.Encoding.PEM)
         )
 
-    print("Built certificate for %s" % hostname)
+    _LOGGER.info("Built certificate for {hostname}", hostname=hostname)
 
 
 def _build_certs():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/txsni-0.1.9/txsni/test/test_txsni.py 
new/txsni-0.2.0/txsni/test/test_txsni.py
--- old/txsni-0.1.9/txsni/test/test_txsni.py    2017-05-25 04:03:50.000000000 
+0200
+++ new/txsni-0.2.0/txsni/test/test_txsni.py    2020-04-06 08:15:02.000000000 
+0200
@@ -1,11 +1,14 @@
 from __future__ import absolute_import
 
-import os
+from functools import partial
 
 from txsni.snimap import SNIMap, HostDirectoryMap
 from txsni.tlsendpoint import TLSEndpoint
+from txsni.only_noticed_pypi_pem_after_i_wrote_this import objectsFromPEM
+from txsni.parser import SNIDirectoryParser
 
 from OpenSSL.crypto import load_certificate, FILETYPE_PEM
+from OpenSSL.SSL import Context, SSLv23_METHOD, Connection
 
 from twisted.internet import protocol, endpoints, reactor, defer, interfaces
 from twisted.internet.ssl import (
@@ -17,7 +20,7 @@
 from zope.interface import implementer
 
 from .certs.cert_builder import (
-    ROOT_CERT_PATH, HTTP2BIN_CERT_PATH, _build_certs, CERT_DIR
+    ROOT_CERT_PATH, HTTP2BIN_CERT_PATH, CERT_DIR, _build_certs,
 )
 
 # We need some temporary certs.
@@ -47,7 +50,13 @@
     return wrapper_endpoint
 
 
-def handshake(client_factory, server_factory, hostname, server_endpoint):
+def handshake(
+        client_factory,
+        server_factory,
+        hostname,
+        server_endpoint,
+        acceptable_protocols=None,
+):
     """
     Connect a basic Twisted TLS client endpoint to the provided TxSNI
     TLSEndpoint. Returns a Deferred that fires when the connection has been
@@ -56,12 +65,18 @@
     """
     def connect_client(listening_port):
         port_number = listening_port.getHost().port
-
         client = endpoints.TCP4ClientEndpoint(
             reactor, '127.0.0.1', port_number
         )
+
+        maybe_alpn = {}
+        if acceptable_protocols is not None:
+            maybe_alpn['acceptableProtocols'] = acceptable_protocols
+
         options = optionsForClientTLS(
-            hostname=hostname, trustRoot=PEM_ROOT
+            hostname=hostname,
+            trustRoot=PEM_ROOT,
+            **maybe_alpn
         )
         client = endpoints.wrapClientTLS(options, client)
         connectDeferred = client.connect(client_factory)
@@ -88,11 +103,8 @@
 
     def dataReceived(self, data):
         cert = self.transport.getPeerCertificate()
+        proto = self.transport.negotiatedProtocol
 
-        if not skipNegotiation:
-            proto = self.transport.negotiatedProtocol
-        else:
-            proto = None
         self.transport.abortConnection()
         self.handshake_deferred.callback((cert, proto))
         self.handshake_deferred = None
@@ -120,23 +132,18 @@
         self.transport.loseConnection()
 
 
-try:
-    @implementer(interfaces.IProtocolNegotiationFactory)
-    class NegotiatingFactory(protocol.Factory):
-        """
-        A Twisted Protocol Factory that implements the protocol negotiation
-        extensions
-        """
-        def acceptableProtocols(self):
-            return [b'h2', b'http/1.1']
-
-    class WritingNegotiatingFactory(WritingProtocolFactory,
-                                    NegotiatingFactory):
-        pass
-
-    skipNegotiation = False
-except AttributeError:
-    skipNegotiation = "IProtocolNegotiationFactory not supported"
+@implementer(interfaces.IProtocolNegotiationFactory)
+class NegotiatingFactory(protocol.Factory):
+    """
+    A Twisted Protocol Factory that implements the protocol negotiation
+    extensions
+    """
+    def acceptableProtocols(self):
+        return [b'h2', b'http/1.1']
+
+class WritingNegotiatingFactory(WritingProtocolFactory,
+                                NegotiatingFactory):
+    pass
 
 
 class TestSNIMap(unittest.TestCase):
@@ -168,24 +175,26 @@
         self.assertIsNot(conn.get_context(), options.getContext())
         self.assertIsNotNone(conn.get_context())
 
+def assert_cert_is(test_case, protocol_cert, cert_path):
+    """
+    Assert that ``protocol_cert`` is the same certificate as the one at
+    ``cert_path``.
+    """
+    with open(cert_path, 'rb') as f:
+        target_cert = load_certificate(FILETYPE_PEM, f.read())
+
+    test_case.assertEqual(
+        protocol_cert.digest('sha256'),
+        target_cert.digest('sha256')
+    )
+
+
 
 class TestCommunication(unittest.TestCase):
     """
     Tests that use the full Twisted logic to validate that txsni works as
     expected.
     """
-    def assertCertIs(self, protocol_cert, cert_path):
-        """
-        Assert that ``protocol_cert`` is the same certificate as the one at
-        ``cert_path``.
-        """
-        with open(cert_path, 'rb') as f:
-            target_cert = load_certificate(FILETYPE_PEM, f.read())
-
-        self.assertEqual(
-            protocol_cert.digest('sha256'),
-            target_cert.digest('sha256')
-        )
 
     def test_specific_certificate(self):
         """
@@ -206,7 +215,7 @@
 
         def confirm_cert(args):
             cert, proto = args
-            self.assertCertIs(cert, HTTP2BIN_CERT_PATH)
+            assert_cert_is(self, cert, HTTP2BIN_CERT_PATH)
             return d
 
         def close(args):
@@ -218,16 +227,42 @@
         return handshake_deferred
 
 
+class TestPemObjects(unittest.TestCase, object):
+    """
+    Tests for L{objectsFromPEM}
+    """
+
+    def test_noObjects(self):
+        """
+        The empty string returns an empty list of certificates.
+        """
+
+        objects = objectsFromPEM(b"")
+        self.assertEqual(objects.certificates, [])
+        self.assertEqual(objects.keys, [])
+
+
+
+def will_use_tls_1_3():
+    """
+    Will OpenSSL negotiate TLS 1.3?
+    """
+    ctx = Context(SSLv23_METHOD)
+    connection = Connection(ctx, None)
+    return connection.get_protocol_version_name() == u'TLSv1.3'
+
+
 class TestNegotiationStillWorks(unittest.TestCase):
     """
     Tests that TxSNI doesn't break protocol negotiation.
     """
-    if skipNegotiation:
-        skip = skipNegotiation
 
-    def test_specific_cert_still_negotiates(self):
+    EXPECTED_PROTOCOL = b'h2'
+
+    def assert_specific_cert_still_negotiates(self, perform_handshake):
         """
-        When TxSNI selects a specific cert, protocol negotiation still works.
+        When TxSNI selects a specific cert, protocol negotiation still
+        works.
         """
         handshake_deferred = defer.Deferred()
         client_factory = WritingNegotiatingFactory(handshake_deferred)
@@ -236,7 +271,7 @@
         )
 
         endpoint = sni_endpoint()
-        d = handshake(
+        d = perform_handshake(
             client_factory=client_factory,
             server_factory=server_factory,
             hostname=u'http2bin.org',
@@ -245,7 +280,7 @@
 
         def confirm_cert(args):
             cert, proto = args
-            self.assertEqual(proto, b'h2')
+            self.assertEqual(proto, self.EXPECTED_PROTOCOL)
             return d
 
         def close(args):
@@ -255,3 +290,89 @@
         handshake_deferred.addCallback(confirm_cert)
         handshake_deferred.addCallback(close)
         return handshake_deferred
+
+
+    def test_specific_cert_still_negotiates_with_alpn(self):
+        """
+        When TxSNI selects a specific cert, Application Level Protocol
+        Negotiation (ALPN) still works.
+        """
+        return self.assert_specific_cert_still_negotiates(
+            partial(handshake, acceptable_protocols=[self.EXPECTED_PROTOCOL])
+        )
+
+
+    def test_specific_cert_still_negotiates_with_npn(self):
+        """
+        When TxSNI selects a specific cert, Next Protocol Negotiation
+        (NPN) still works.
+        """
+        return self.assert_specific_cert_still_negotiates(handshake)
+
+    if will_use_tls_1_3():
+        test_specific_cert_still_negotiates_with_npn.skip = (
+            "OpenSSL does not support NPN with TLS 1.3"
+        )
+
+
+class TestSNIDirectoryParser(unittest.TestCase):
+    """
+    Tests the C{txsni} endpoint implementation.
+    """
+
+    def setUp(self):
+        self.directory_parser = SNIDirectoryParser()
+
+    def test_recreated_certificates(self):
+        """
+        L{SNIDirectoryParser} always uses the latest certificate for
+        the requested domain.
+        """
+        endpoint = self.directory_parser.parseStreamServer(
+                reactor, CERT_DIR, 'tcp', port='0', interface='127.0.0.1')
+
+        def handshake_and_check(_):
+            handshake_deferred = defer.Deferred()
+            client_factory = WritingProtocolFactory(handshake_deferred)
+            server_factory = protocol.Factory.forProtocol(WriteBackProtocol)
+
+            initiate_handshake_deferred = handshake(
+                    client_factory=client_factory,
+                    server_factory=server_factory,
+                    hostname=u"http2bin.org",
+                    server_endpoint=endpoint,
+                )
+
+            def confirm_cert(args):
+                cert, proto = args
+                assert_cert_is(self, cert, HTTP2BIN_CERT_PATH)
+
+            def close(args):
+                client, port = args
+                port.stopListening()
+
+            exception = [None]
+
+            def captureException(f):
+                exception[0] = f
+
+            def maybeRethrow(_):
+                if exception[0] is not None:
+                    exception[0].raiseException()
+
+            handshake_deferred.addCallback(confirm_cert)
+            handshake_deferred.addErrback(captureException)
+
+            handshake_deferred.addCallback(lambda _: 
initiate_handshake_deferred)
+            handshake_deferred.addCallback(close)
+
+            handshake_deferred.addCallback(maybeRethrow)
+            return handshake_deferred
+
+        def reset_http2bin_cert(_):
+            FilePath(HTTP2BIN_CERT_PATH).remove()
+            _build_certs()
+
+        old_cert_handshake = handshake_and_check(None)
+        old_cert_handshake.addCallback(reset_http2bin_cert)
+        return old_cert_handshake.addCallback(handshake_and_check)


Reply via email to