mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 00:01:36 +00:00
Merge pull request #2469 from Kriechi/nuke-old-openssl
nuke old openssl
This commit is contained in:
commit
d409a6c09a
@ -1,7 +1,6 @@
|
|||||||
from mitmproxy.addons import allowremote
|
from mitmproxy.addons import allowremote
|
||||||
from mitmproxy.addons import anticache
|
from mitmproxy.addons import anticache
|
||||||
from mitmproxy.addons import anticomp
|
from mitmproxy.addons import anticomp
|
||||||
from mitmproxy.addons import check_alpn
|
|
||||||
from mitmproxy.addons import check_ca
|
from mitmproxy.addons import check_ca
|
||||||
from mitmproxy.addons import clientplayback
|
from mitmproxy.addons import clientplayback
|
||||||
from mitmproxy.addons import core_option_validation
|
from mitmproxy.addons import core_option_validation
|
||||||
@ -29,7 +28,6 @@ def default_addons():
|
|||||||
allowremote.AllowRemote(),
|
allowremote.AllowRemote(),
|
||||||
anticache.AntiCache(),
|
anticache.AntiCache(),
|
||||||
anticomp.AntiComp(),
|
anticomp.AntiComp(),
|
||||||
check_alpn.CheckALPN(),
|
|
||||||
check_ca.CheckCA(),
|
check_ca.CheckCA(),
|
||||||
clientplayback.ClientPlayback(),
|
clientplayback.ClientPlayback(),
|
||||||
cut.Cut(),
|
cut.Cut(),
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
import mitmproxy
|
|
||||||
from mitmproxy.net import tcp
|
|
||||||
from mitmproxy import ctx
|
|
||||||
|
|
||||||
|
|
||||||
class CheckALPN:
|
|
||||||
def __init__(self):
|
|
||||||
self.failed = False
|
|
||||||
|
|
||||||
def configure(self, updated):
|
|
||||||
self.failed = mitmproxy.ctx.master.options.http2 and not tcp.HAS_ALPN
|
|
||||||
if self.failed:
|
|
||||||
ctx.log.warn(
|
|
||||||
"HTTP/2 is disabled because ALPN support missing!\n"
|
|
||||||
"OpenSSL 1.0.2+ required to support HTTP/2 connections.\n"
|
|
||||||
"Use --no-http2 to silence this warning."
|
|
||||||
)
|
|
@ -14,18 +14,12 @@ from typing import Optional # noqa
|
|||||||
from mitmproxy.utils import strutils
|
from mitmproxy.utils import strutils
|
||||||
|
|
||||||
import certifi
|
import certifi
|
||||||
import OpenSSL
|
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
|
|
||||||
from mitmproxy import certs
|
from mitmproxy import certs
|
||||||
from mitmproxy.utils import version_check
|
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy.types import basethread
|
from mitmproxy.types import basethread
|
||||||
|
|
||||||
# This is a rather hackish way to make sure that
|
|
||||||
# the latest version of pyOpenSSL is actually installed.
|
|
||||||
version_check.check_pyopenssl_version()
|
|
||||||
|
|
||||||
socket_fileobject = socket.SocketIO
|
socket_fileobject = socket.SocketIO
|
||||||
|
|
||||||
# workaround for https://bugs.python.org/issue29515
|
# workaround for https://bugs.python.org/issue29515
|
||||||
@ -33,7 +27,6 @@ socket_fileobject = socket.SocketIO
|
|||||||
IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41)
|
IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41)
|
||||||
|
|
||||||
EINTR = 4
|
EINTR = 4
|
||||||
HAS_ALPN = SSL._lib.Cryptography_HAS_ALPN
|
|
||||||
|
|
||||||
# To enable all SSL methods use: SSLv23
|
# To enable all SSL methods use: SSLv23
|
||||||
# then add options to disable certain methods
|
# then add options to disable certain methods
|
||||||
@ -503,7 +496,6 @@ class _Connection:
|
|||||||
if cipher_list:
|
if cipher_list:
|
||||||
try:
|
try:
|
||||||
context.set_cipher_list(cipher_list.encode())
|
context.set_cipher_list(cipher_list.encode())
|
||||||
context.set_tmp_ecdh(OpenSSL.crypto.get_elliptic_curve('prime256v1'))
|
|
||||||
except SSL.Error as v:
|
except SSL.Error as v:
|
||||||
raise exceptions.TlsException("SSL cipher specification error: %s" % str(v))
|
raise exceptions.TlsException("SSL cipher specification error: %s" % str(v))
|
||||||
|
|
||||||
@ -511,24 +503,23 @@ class _Connection:
|
|||||||
if log_ssl_key:
|
if log_ssl_key:
|
||||||
context.set_info_callback(log_ssl_key)
|
context.set_info_callback(log_ssl_key)
|
||||||
|
|
||||||
if HAS_ALPN: # pragma: openssl-old no cover
|
if alpn_protos is not None:
|
||||||
if alpn_protos is not None:
|
# advertise application layer protocols
|
||||||
# advertise application layer protocols
|
context.set_alpn_protos(alpn_protos)
|
||||||
context.set_alpn_protos(alpn_protos)
|
elif alpn_select is not None and alpn_select_callback is None:
|
||||||
elif alpn_select is not None and alpn_select_callback is None:
|
# select application layer protocol
|
||||||
# select application layer protocol
|
def alpn_select_callback(conn_, options):
|
||||||
def alpn_select_callback(conn_, options):
|
if alpn_select in options:
|
||||||
if alpn_select in options:
|
return bytes(alpn_select)
|
||||||
return bytes(alpn_select)
|
else: # pragma: no cover
|
||||||
else: # pragma: no cover
|
return options[0]
|
||||||
return options[0]
|
context.set_alpn_select_callback(alpn_select_callback)
|
||||||
context.set_alpn_select_callback(alpn_select_callback)
|
elif alpn_select_callback is not None and alpn_select is None:
|
||||||
elif alpn_select_callback is not None and alpn_select is None:
|
if not callable(alpn_select_callback):
|
||||||
if not callable(alpn_select_callback):
|
raise exceptions.TlsException("ALPN error: alpn_select_callback must be a function.")
|
||||||
raise exceptions.TlsException("ALPN error: alpn_select_callback must be a function.")
|
context.set_alpn_select_callback(alpn_select_callback)
|
||||||
context.set_alpn_select_callback(alpn_select_callback)
|
elif alpn_select_callback is not None and alpn_select is not None:
|
||||||
elif alpn_select_callback is not None and alpn_select is not None:
|
raise exceptions.TlsException("ALPN error: only define alpn_select (string) OR alpn_select_callback (function).")
|
||||||
raise exceptions.TlsException("ALPN error: only define alpn_select (string) OR alpn_select_callback (function).")
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@ -720,7 +711,7 @@ class TCPClient(_Connection):
|
|||||||
return self.connection.gettimeout()
|
return self.connection.gettimeout()
|
||||||
|
|
||||||
def get_alpn_proto_negotiated(self):
|
def get_alpn_proto_negotiated(self):
|
||||||
if HAS_ALPN and self.ssl_established: # pragma: openssl-old no cover
|
if self.ssl_established:
|
||||||
return self.connection.get_alpn_proto_negotiated()
|
return self.connection.get_alpn_proto_negotiated()
|
||||||
else:
|
else:
|
||||||
return b""
|
return b""
|
||||||
@ -827,7 +818,7 @@ class BaseHandler(_Connection):
|
|||||||
self.connection.settimeout(n)
|
self.connection.settimeout(n)
|
||||||
|
|
||||||
def get_alpn_proto_negotiated(self):
|
def get_alpn_proto_negotiated(self):
|
||||||
if HAS_ALPN and self.ssl_established: # pragma: openssl-old no cover
|
if self.ssl_established:
|
||||||
return self.connection.get_alpn_proto_negotiated()
|
return self.connection.get_alpn_proto_negotiated()
|
||||||
else:
|
else:
|
||||||
return b""
|
return b""
|
||||||
|
@ -16,7 +16,6 @@ from mitmproxy import exceptions # noqa
|
|||||||
from mitmproxy import options # noqa
|
from mitmproxy import options # noqa
|
||||||
from mitmproxy import optmanager # noqa
|
from mitmproxy import optmanager # noqa
|
||||||
from mitmproxy import proxy # noqa
|
from mitmproxy import proxy # noqa
|
||||||
from mitmproxy.utils import version_check # noqa
|
|
||||||
from mitmproxy.utils import debug # noqa
|
from mitmproxy.utils import debug # noqa
|
||||||
|
|
||||||
|
|
||||||
@ -58,7 +57,6 @@ def run(MasterKlass, args, extra=None): # pragma: no cover
|
|||||||
extra: Extra argument processing callable which returns a dict of
|
extra: Extra argument processing callable which returns a dict of
|
||||||
options.
|
options.
|
||||||
"""
|
"""
|
||||||
version_check.check_pyopenssl_version()
|
|
||||||
debug.register_info_dumpers()
|
debug.register_info_dumpers()
|
||||||
|
|
||||||
opts = options.Options()
|
opts = options.Options()
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
"""
|
|
||||||
Having installed a wrong version of pyOpenSSL is unfortunately a very common
|
|
||||||
source of error. Check before every start that both versions are somewhat okay.
|
|
||||||
"""
|
|
||||||
import sys
|
|
||||||
import inspect
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
import OpenSSL
|
|
||||||
|
|
||||||
PYOPENSSL_MIN_VERSION = (16, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def check_pyopenssl_version(min_version=PYOPENSSL_MIN_VERSION, fp=sys.stderr):
|
|
||||||
min_version_str = ".".join(str(x) for x in min_version)
|
|
||||||
try:
|
|
||||||
v = tuple(int(x) for x in OpenSSL.__version__.split(".")[:2])
|
|
||||||
except ValueError:
|
|
||||||
print(
|
|
||||||
"Cannot parse pyOpenSSL version: {}"
|
|
||||||
"mitmproxy requires pyOpenSSL {} or greater.".format(
|
|
||||||
OpenSSL.__version__, min_version_str
|
|
||||||
),
|
|
||||||
file=fp
|
|
||||||
)
|
|
||||||
return
|
|
||||||
if v < min_version:
|
|
||||||
print(
|
|
||||||
"You are using an outdated version of pyOpenSSL: "
|
|
||||||
"mitmproxy requires pyOpenSSL {} or greater.".format(min_version_str),
|
|
||||||
file=fp
|
|
||||||
)
|
|
||||||
# Some users apparently have multiple versions of pyOpenSSL installed.
|
|
||||||
# Report which one we got.
|
|
||||||
pyopenssl_path = os.path.dirname(inspect.getfile(OpenSSL))
|
|
||||||
print(
|
|
||||||
"Your pyOpenSSL {} installation is located at {}".format(
|
|
||||||
OpenSSL.__version__, pyopenssl_path
|
|
||||||
),
|
|
||||||
file=fp
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
@ -223,14 +223,6 @@ class Pathoc(tcp.TCPClient):
|
|||||||
self.ws_framereader = None
|
self.ws_framereader = None
|
||||||
|
|
||||||
if self.use_http2:
|
if self.use_http2:
|
||||||
if not tcp.HAS_ALPN: # pragma: no cover
|
|
||||||
log.write_raw(
|
|
||||||
self.fp,
|
|
||||||
"HTTP/2 requires ALPN support. "
|
|
||||||
"Please use OpenSSL >= 1.0.2. "
|
|
||||||
"Pathoc might not be working as expected without ALPN.",
|
|
||||||
timestamp=False
|
|
||||||
)
|
|
||||||
self.protocol = http2.HTTP2StateProtocol(self, dump_frames=self.http2_framedump)
|
self.protocol = http2.HTTP2StateProtocol(self, dump_frames=self.http2_framedump)
|
||||||
else:
|
else:
|
||||||
self.protocol = net_http.http1
|
self.protocol = net_http.http1
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
import OpenSSL
|
|
||||||
|
|
||||||
import mitmproxy.net.tcp
|
|
||||||
|
|
||||||
pytest_plugins = ('test.full_coverage_plugin',)
|
pytest_plugins = ('test.full_coverage_plugin',)
|
||||||
|
|
||||||
requires_alpn = pytest.mark.skipif(
|
|
||||||
not mitmproxy.net.tcp.HAS_ALPN,
|
|
||||||
reason='requires OpenSSL with ALPN support')
|
|
||||||
|
|
||||||
skip_windows = pytest.mark.skipif(
|
skip_windows = pytest.mark.skipif(
|
||||||
os.name == "nt",
|
os.name == "nt",
|
||||||
reason='Skipping due to Windows'
|
reason='Skipping due to Windows'
|
||||||
@ -24,9 +17,3 @@ skip_appveyor = pytest.mark.skipif(
|
|||||||
"APPVEYOR" in os.environ,
|
"APPVEYOR" in os.environ,
|
||||||
reason='Skipping due to Appveyor'
|
reason='Skipping due to Appveyor'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def disable_alpn(monkeypatch):
|
|
||||||
monkeypatch.setattr(mitmproxy.net.tcp, 'HAS_ALPN', False)
|
|
||||||
monkeypatch.setattr(OpenSSL.SSL._lib, 'Cryptography_HAS_ALPN', False)
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
from mitmproxy.addons import check_alpn
|
|
||||||
from mitmproxy.test import taddons
|
|
||||||
from ...conftest import requires_alpn
|
|
||||||
|
|
||||||
|
|
||||||
class TestCheckALPN:
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
def test_check_alpn(self):
|
|
||||||
msg = 'ALPN support missing'
|
|
||||||
|
|
||||||
with taddons.context() as tctx:
|
|
||||||
a = check_alpn.CheckALPN()
|
|
||||||
tctx.configure(a)
|
|
||||||
assert not tctx.master.has_log(msg)
|
|
||||||
|
|
||||||
def test_check_no_alpn(self, disable_alpn):
|
|
||||||
msg = 'ALPN support missing'
|
|
||||||
|
|
||||||
with taddons.context() as tctx:
|
|
||||||
a = check_alpn.CheckALPN()
|
|
||||||
tctx.configure(a)
|
|
||||||
assert tctx.master.has_log(msg)
|
|
@ -1,20 +1,84 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIIBOQIBAAJBAKVJ43C+8SjOvN9/pP/8HwzmHGQmRvdK/R6KlWdr7He6iiXDQNfH
|
MIIJKgIBAAKCAgEA4Jut+R51opC773ToeUhwJOVGnpxNqzZTDMImO141WPvKMjMs
|
||||||
RAp+gqX0hBRT80eRjGhSmTTBLCWiXVny4UUCAwEAAQJAUQ8nZ0d85VJd9g2XUaLH
|
i15f0U3OKqK8YERDfDzaAbgqz6MNgqc8QbNJ0e9VxtMUzTkCwSlbDHMFgZNyXVRX
|
||||||
Z4ACNGtBKk2wTKYSFyIqWZxsF5qhh7HGshJIAP6tYiX8ZW+mMSfme+zsJzWe8ChL
|
OQEBJ/fTMlU+LimOH38QY0orifdAHH+kPUYIiqTBzgJvCy8w1o4hGSlzf2HW400d
|
||||||
gQIhAM8QpAgUHnNteZvkv0XqceX1GILEWifMt+hO9yTp4dY5AiEAzFnKr77CKCri
|
mlRSJEVgBj6nXQENbVxmxf6f9H19eWpnLuP5aJIwP4LEsGdqLP0ESnWfZVPIAiEs
|
||||||
/DPig4R/5q4KMpMx9EqJufHdGNmIA20CICMARxnufK86RCIr6oEg/hvG8Fu6YRr1
|
LuYkhbRXqiuJfnc1am8LexzLi4VQMCw0K4Tm1lTbapcnOUakO6orQvX7MOEKYBU+
|
||||||
Kekk3/XnavtRAiBVLVQ7vwKE5aNpRmMzOKZrS736aLpYvjz8IaFr+zgjXQIgdad5
|
ogGGby0MyOTaCkuUFi0YdTtU4DEdWJ9HfogRO/uG1325/8/T+tq8RgOkp9cUvjU3
|
||||||
QZoTD49NTyMEgyZp70gTXcXQLrX2PgQKL4uNmoU=
|
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
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIBgTCCASugAwIBAgIJAKlcXsPLQAQuMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
|
MIIFtTCCA52gAwIBAgIJAM/qkBYP5ExSMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
||||||
BAYTAkFVMB4XDTEzMTIxMjAxMzA1NVoXDTE0MDExMTAxMzA1NVowDTELMAkGA1UE
|
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
|
||||||
BhMCQVUwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApUnjcL7xKM6833+k//wfDOYc
|
aWRnaXRzIFB0eSBMdGQwHhcNMTcwNzI1MDg0MDAwWhcNMTgwNzI1MDg0MDAwWjBF
|
||||||
ZCZG90r9HoqVZ2vsd7qKJcNA18dECn6CpfSEFFPzR5GMaFKZNMEsJaJdWfLhRQID
|
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
|
||||||
AQABo24wbDAdBgNVHQ4EFgQUJm8BXcVRsROy0PVt5stkB3eVnEgwPQYDVR0jBDYw
|
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
||||||
NIAUJm8BXcVRsROy0PVt5stkB3eVnEihEaQPMA0xCzAJBgNVBAYTAkFVggkAqVxe
|
CgKCAgEA4Jut+R51opC773ToeUhwJOVGnpxNqzZTDMImO141WPvKMjMsi15f0U3O
|
||||||
w8tABC4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAHHxcBEpWrIqtLVH
|
KqK8YERDfDzaAbgqz6MNgqc8QbNJ0e9VxtMUzTkCwSlbDHMFgZNyXVRXOQEBJ/fT
|
||||||
m6Yn1hgqrAbfMj9IK6zY9C5Cbad/DfUj3AZMb5u758WJK0x9brmckgqdrQsuf9He
|
MlU+LimOH38QY0orifdAHH+kPUYIiqTBzgJvCy8w1o4hGSlzf2HW400dmlRSJEVg
|
||||||
Ef51/SU=
|
Bj6nXQENbVxmxf6f9H19eWpnLuP5aJIwP4LEsGdqLP0ESnWfZVPIAiEsLuYkhbRX
|
||||||
|
qiuJfnc1am8LexzLi4VQMCw0K4Tm1lTbapcnOUakO6orQvX7MOEKYBU+ogGGby0M
|
||||||
|
yOTaCkuUFi0YdTtU4DEdWJ9HfogRO/uG1325/8/T+tq8RgOkp9cUvjU3ONqpLZC6
|
||||||
|
zs0YR8OzlTbXClmV+Mr6d1qEb3jk6zWlLykLVozOS3z5vdVxpbJqM/CtHporAA0c
|
||||||
|
Ser2EGtN68OB3Hy3Bh7MPjqpSFSJ1uTQ755jS3qOzwggoQFCz2dBmfyi7nOGHFW4
|
||||||
|
h/5NaF1mnIlJJVnJIZajSNl9e6klGeXmJv4ZtiqJd/CG0jTUnGWOTimukSmxVNcW
|
||||||
|
s2vFjwQhuRJwawzGo7O1gZPkq3/0/F+yLp5karmRJs8sQ/JDvGL4rW5YqW7u1WuY
|
||||||
|
QeHYHscfPwf0be8teKWcURIqBoHPxdJV3s9zf8Y/AN9OFFdPqwcCAwEAAaOBpzCB
|
||||||
|
pDAdBgNVHQ4EFgQUZrQUSE9A8i0N4ZuQZq/F4I74QlwwdQYDVR0jBG4wbIAUZrQU
|
||||||
|
SE9A8i0N4ZuQZq/F4I74QlyhSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpT
|
||||||
|
b21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCCQDP
|
||||||
|
6pAWD+RMUjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQDPeylCUY4k
|
||||||
|
nG1KoT139g5T5G1/lxgmYnDqQB1+5JYCQWsPK7sy19tD58bq3+2N2Tozu2/f/GkG
|
||||||
|
LZtouLyRciFtcAWy4LQlSR4hTLAWeik2WV/h+ovfv4XwvRuwS5PYVQNHQsOAO3ea
|
||||||
|
hX+W+w+rwI+MFlgEHJO85P61ijcNVbiTpgd0s47RViKyJVDqfhCmpobzS5eTbbXn
|
||||||
|
F1oFlV84lgEt84BE4RJxlr6fSIxZn6rQPjdbY65snol7Zs2oAt7nLb3hpZgWKobF
|
||||||
|
3xAfkC9m19nQHeYz3JlNC7sf80top2H2HEZMVVOAD+MxXkcAjNbjBRT3/KAIyWex
|
||||||
|
2fmoGRbvCIU0LFyyyk7/tG1xTgxNuBmd4Byz1LI25uz6eK4Ey8LeZmp5mvaewI53
|
||||||
|
t65sAGBkx+LIRt0yGmMCRRFl735Ya4SJD7je1GTiw9I3Yd63dtaJTVd65kkFkLOk
|
||||||
|
LD56iJHSyCY6JkDXd8RjozIVoaXkVQh2wFq/ZfXzAgIx/u5cJQCMG2DAu6/WI74+
|
||||||
|
7invOv7dbYfoI02N4iB57iRbPxE4gSrRayYxUVdH1R/tlXbN9Fkd30fl2WfSO897
|
||||||
|
QC/ODA9w86FSFANhn6nv2KuKIMUSEW+5ZhBowSFIBEdAaMS7yj9uuBWmQKrWNfOh
|
||||||
|
mZJF1YiFmgRybkdKHPrlCSZyvVBdmnmM6g==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
@ -3,7 +3,6 @@ import queue
|
|||||||
import time
|
import time
|
||||||
import socket
|
import socket
|
||||||
import random
|
import random
|
||||||
import os
|
|
||||||
import threading
|
import threading
|
||||||
import pytest
|
import pytest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
@ -15,7 +14,6 @@ from mitmproxy import exceptions
|
|||||||
from mitmproxy.test import tutils
|
from mitmproxy.test import tutils
|
||||||
|
|
||||||
from . import tservers
|
from . import tservers
|
||||||
from ...conftest import requires_alpn
|
|
||||||
|
|
||||||
|
|
||||||
class EchoHandler(tcp.BaseHandler):
|
class EchoHandler(tcp.BaseHandler):
|
||||||
@ -534,36 +532,18 @@ class TestTimeOut(tservers.ServerTestBase):
|
|||||||
c.rfile.read(10)
|
c.rfile.read(10)
|
||||||
|
|
||||||
|
|
||||||
class TestCryptographyALPN:
|
|
||||||
|
|
||||||
def test_has_alpn(self):
|
|
||||||
if os.environ.get("OPENSSL") == "with-alpn":
|
|
||||||
assert tcp.HAS_ALPN
|
|
||||||
assert SSL._lib.Cryptography_HAS_ALPN
|
|
||||||
elif os.environ.get("OPENSSL") == "old":
|
|
||||||
assert not tcp.HAS_ALPN
|
|
||||||
assert not SSL._lib.Cryptography_HAS_ALPN
|
|
||||||
|
|
||||||
|
|
||||||
class TestALPNClient(tservers.ServerTestBase):
|
class TestALPNClient(tservers.ServerTestBase):
|
||||||
handler = ALPNHandler
|
handler = ALPNHandler
|
||||||
ssl = dict(
|
ssl = dict(
|
||||||
alpn_select=b"bar"
|
alpn_select=b"bar"
|
||||||
)
|
)
|
||||||
|
|
||||||
@requires_alpn
|
@pytest.mark.parametrize('alpn_protos, expected_negotiated, expected_response', [
|
||||||
@pytest.mark.parametrize('has_alpn,alpn_protos, expected_negotiated, expected_response', [
|
([b"foo", b"bar", b"fasel"], b'bar', b'bar'),
|
||||||
(True, [b"foo", b"bar", b"fasel"], b'bar', b'bar'),
|
([], b'', b'NONE'),
|
||||||
(True, [], b'', b'NONE'),
|
(None, b'', b'NONE'),
|
||||||
(True, None, b'', b'NONE'),
|
|
||||||
(False, [b"foo", b"bar", b"fasel"], b'', b'NONE'),
|
|
||||||
(False, [], b'', b'NONE'),
|
|
||||||
(False, None, b'', b'NONE'),
|
|
||||||
])
|
])
|
||||||
def test_alpn(self, monkeypatch, has_alpn, alpn_protos, expected_negotiated, expected_response):
|
def test_alpn(self, monkeypatch, alpn_protos, expected_negotiated, expected_response):
|
||||||
monkeypatch.setattr(tcp, 'HAS_ALPN', has_alpn)
|
|
||||||
monkeypatch.setattr(SSL._lib, 'Cryptography_HAS_ALPN', has_alpn)
|
|
||||||
|
|
||||||
c = tcp.TCPClient(("127.0.0.1", self.port))
|
c = tcp.TCPClient(("127.0.0.1", self.port))
|
||||||
with c.connect():
|
with c.connect():
|
||||||
c.convert_to_ssl(alpn_protos=alpn_protos)
|
c.convert_to_ssl(alpn_protos=alpn_protos)
|
||||||
@ -574,7 +554,7 @@ class TestALPNClient(tservers.ServerTestBase):
|
|||||||
class TestNoSSLNoALPNClient(tservers.ServerTestBase):
|
class TestNoSSLNoALPNClient(tservers.ServerTestBase):
|
||||||
handler = ALPNHandler
|
handler = ALPNHandler
|
||||||
|
|
||||||
def test_no_ssl_no_alpn(self, disable_alpn):
|
def test_no_ssl_no_alpn(self):
|
||||||
c = tcp.TCPClient(("127.0.0.1", self.port))
|
c = tcp.TCPClient(("127.0.0.1", self.port))
|
||||||
with c.connect():
|
with c.connect():
|
||||||
assert c.get_alpn_proto_negotiated() == b""
|
assert c.get_alpn_proto_negotiated() == b""
|
||||||
@ -857,9 +837,8 @@ class TestSSLInvalid(tservers.ServerTestBase):
|
|||||||
def test_alpn_error(self):
|
def test_alpn_error(self):
|
||||||
c = tcp.TCPClient(("127.0.0.1", self.port))
|
c = tcp.TCPClient(("127.0.0.1", self.port))
|
||||||
with c.connect():
|
with c.connect():
|
||||||
if tcp.HAS_ALPN:
|
with pytest.raises(exceptions.TlsException, match="must be a function"):
|
||||||
with pytest.raises(exceptions.TlsException, match="must be a function"):
|
c.create_ssl_context(alpn_select_callback="foo")
|
||||||
c.create_ssl_context(alpn_select_callback="foo")
|
|
||||||
|
|
||||||
with pytest.raises(exceptions.TlsException, match="ALPN error"):
|
with pytest.raises(exceptions.TlsException, match="ALPN error"):
|
||||||
c.create_ssl_context(alpn_select="foo", alpn_select_callback="bar")
|
c.create_ssl_context(alpn_select="foo", alpn_select_callback="bar")
|
||||||
|
@ -17,7 +17,6 @@ from mitmproxy.net.http import http1, http2
|
|||||||
from pathod.language import generators
|
from pathod.language import generators
|
||||||
|
|
||||||
from ... import tservers
|
from ... import tservers
|
||||||
from ....conftest import requires_alpn
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logging.getLogger("hyper.packages.hpack.hpack").setLevel(logging.WARNING)
|
logging.getLogger("hyper.packages.hpack.hpack").setLevel(logging.WARNING)
|
||||||
@ -203,7 +202,6 @@ class _Http2Test(_Http2TestBase, _Http2ServerBase):
|
|||||||
_Http2ServerBase.teardown_class()
|
_Http2ServerBase.teardown_class()
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestSimple(_Http2Test):
|
class TestSimple(_Http2Test):
|
||||||
request_body_buffer = b''
|
request_body_buffer = b''
|
||||||
|
|
||||||
@ -286,7 +284,6 @@ class TestSimple(_Http2Test):
|
|||||||
assert response_body_buffer == b'response body'
|
assert response_body_buffer == b'response body'
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestRequestWithPriority(_Http2Test):
|
class TestRequestWithPriority(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -368,7 +365,6 @@ class TestRequestWithPriority(_Http2Test):
|
|||||||
assert resp.headers.get('priority_weight', None) == expected_priority[2]
|
assert resp.headers.get('priority_weight', None) == expected_priority[2]
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestPriority(_Http2Test):
|
class TestPriority(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -453,7 +449,6 @@ class TestPriority(_Http2Test):
|
|||||||
assert self.priority_data == expected_priority
|
assert self.priority_data == expected_priority
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestStreamResetFromServer(_Http2Test):
|
class TestStreamResetFromServer(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -504,7 +499,6 @@ class TestStreamResetFromServer(_Http2Test):
|
|||||||
assert self.master.state.flows[0].response is None
|
assert self.master.state.flows[0].response is None
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestBodySizeLimit(_Http2Test):
|
class TestBodySizeLimit(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -554,7 +548,6 @@ class TestBodySizeLimit(_Http2Test):
|
|||||||
assert len(self.master.state.flows) == 0
|
assert len(self.master.state.flows) == 0
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestPushPromise(_Http2Test):
|
class TestPushPromise(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -723,7 +716,6 @@ class TestPushPromise(_Http2Test):
|
|||||||
# the other two bodies might not be transmitted before the reset
|
# the other two bodies might not be transmitted before the reset
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestConnectionLost(_Http2Test):
|
class TestConnectionLost(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -765,7 +757,6 @@ class TestConnectionLost(_Http2Test):
|
|||||||
assert self.master.state.flows[0].response is None
|
assert self.master.state.flows[0].response is None
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestMaxConcurrentStreams(_Http2Test):
|
class TestMaxConcurrentStreams(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -826,7 +817,6 @@ class TestMaxConcurrentStreams(_Http2Test):
|
|||||||
assert b"Stream-ID " in flow.response.content
|
assert b"Stream-ID " in flow.response.content
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestConnectionTerminated(_Http2Test):
|
class TestConnectionTerminated(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -867,7 +857,6 @@ class TestConnectionTerminated(_Http2Test):
|
|||||||
assert connection_terminated_event.additional_data == b'foobar'
|
assert connection_terminated_event.additional_data == b'foobar'
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestRequestStreaming(_Http2Test):
|
class TestRequestStreaming(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -926,7 +915,6 @@ class TestRequestStreaming(_Http2Test):
|
|||||||
assert connection_terminated_event is None
|
assert connection_terminated_event is None
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestResponseStreaming(_Http2Test):
|
class TestResponseStreaming(_Http2Test):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
import io
|
|
||||||
from unittest import mock
|
|
||||||
from mitmproxy.utils import version_check
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch("sys.exit")
|
|
||||||
def test_check_pyopenssl_version(sexit):
|
|
||||||
fp = io.StringIO()
|
|
||||||
version_check.check_pyopenssl_version(fp=fp)
|
|
||||||
assert not fp.getvalue()
|
|
||||||
assert not sexit.called
|
|
||||||
|
|
||||||
version_check.check_pyopenssl_version((9999,), fp=fp)
|
|
||||||
assert "outdated" in fp.getvalue()
|
|
||||||
assert sexit.called
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch("sys.exit")
|
|
||||||
@mock.patch("OpenSSL.__version__")
|
|
||||||
def test_unparseable_pyopenssl_version(version, sexit):
|
|
||||||
version.split.return_value = ["foo", "bar"]
|
|
||||||
fp = io.StringIO()
|
|
||||||
version_check.check_pyopenssl_version(fp=fp)
|
|
||||||
assert "Cannot parse" in fp.getvalue()
|
|
||||||
assert not sexit.called
|
|
@ -11,8 +11,6 @@ from ...mitmproxy.net import tservers as net_tservers
|
|||||||
|
|
||||||
from pathod.protocols.http2 import HTTP2StateProtocol, TCPHandler
|
from pathod.protocols.http2 import HTTP2StateProtocol, TCPHandler
|
||||||
|
|
||||||
from ...conftest import requires_alpn
|
|
||||||
|
|
||||||
|
|
||||||
class TestTCPHandlerWrapper:
|
class TestTCPHandlerWrapper:
|
||||||
def test_wrapped(self):
|
def test_wrapped(self):
|
||||||
@ -68,7 +66,6 @@ class TestProtocol:
|
|||||||
assert mock_server_method.called
|
assert mock_server_method.called
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestCheckALPNMatch(net_tservers.ServerTestBase):
|
class TestCheckALPNMatch(net_tservers.ServerTestBase):
|
||||||
handler = EchoHandler
|
handler = EchoHandler
|
||||||
ssl = dict(
|
ssl = dict(
|
||||||
@ -83,7 +80,6 @@ class TestCheckALPNMatch(net_tservers.ServerTestBase):
|
|||||||
assert protocol.check_alpn()
|
assert protocol.check_alpn()
|
||||||
|
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
class TestCheckALPNMismatch(net_tservers.ServerTestBase):
|
class TestCheckALPNMismatch(net_tservers.ServerTestBase):
|
||||||
handler = EchoHandler
|
handler = EchoHandler
|
||||||
ssl = dict(
|
ssl = dict(
|
||||||
|
@ -11,7 +11,6 @@ from pathod.protocols.http2 import HTTP2StateProtocol
|
|||||||
|
|
||||||
from mitmproxy.test import tutils
|
from mitmproxy.test import tutils
|
||||||
from . import tservers
|
from . import tservers
|
||||||
from ..conftest import requires_alpn
|
|
||||||
|
|
||||||
|
|
||||||
def test_response():
|
def test_response():
|
||||||
@ -216,7 +215,6 @@ class TestDaemonHTTP2(PathocTestDaemon):
|
|||||||
ssl = True
|
ssl = True
|
||||||
explain = False
|
explain = False
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
def test_http2(self):
|
def test_http2(self):
|
||||||
c = pathoc.Pathoc(
|
c = pathoc.Pathoc(
|
||||||
("127.0.0.1", self.d.port),
|
("127.0.0.1", self.d.port),
|
||||||
@ -231,7 +229,6 @@ class TestDaemonHTTP2(PathocTestDaemon):
|
|||||||
)
|
)
|
||||||
assert c.protocol == http1
|
assert c.protocol == http1
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
def test_http2_alpn(self):
|
def test_http2_alpn(self):
|
||||||
c = pathoc.Pathoc(
|
c = pathoc.Pathoc(
|
||||||
("127.0.0.1", self.d.port),
|
("127.0.0.1", self.d.port),
|
||||||
@ -248,7 +245,6 @@ class TestDaemonHTTP2(PathocTestDaemon):
|
|||||||
_, kwargs = c.convert_to_ssl.call_args
|
_, kwargs = c.convert_to_ssl.call_args
|
||||||
assert set(kwargs['alpn_protos']) == set([b'http/1.1', b'h2'])
|
assert set(kwargs['alpn_protos']) == set([b'http/1.1', b'h2'])
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
def test_request(self):
|
def test_request(self):
|
||||||
c = pathoc.Pathoc(
|
c = pathoc.Pathoc(
|
||||||
("127.0.0.1", self.d.port),
|
("127.0.0.1", self.d.port),
|
||||||
@ -259,14 +255,3 @@ class TestDaemonHTTP2(PathocTestDaemon):
|
|||||||
with c.connect():
|
with c.connect():
|
||||||
resp = c.request("get:/p/200")
|
resp = c.request("get:/p/200")
|
||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
|
|
||||||
def test_failing_request(self, disable_alpn):
|
|
||||||
c = pathoc.Pathoc(
|
|
||||||
("127.0.0.1", self.d.port),
|
|
||||||
fp=None,
|
|
||||||
ssl=True,
|
|
||||||
use_http2=True,
|
|
||||||
)
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
with c.connect():
|
|
||||||
c.request("get:/p/200")
|
|
||||||
|
@ -8,7 +8,6 @@ from mitmproxy import exceptions
|
|||||||
from mitmproxy.test import tutils
|
from mitmproxy.test import tutils
|
||||||
|
|
||||||
from . import tservers
|
from . import tservers
|
||||||
from ..conftest import requires_alpn
|
|
||||||
|
|
||||||
|
|
||||||
class TestPathod:
|
class TestPathod:
|
||||||
@ -257,11 +256,6 @@ class TestHTTP2(tservers.DaemonTests):
|
|||||||
ssl = True
|
ssl = True
|
||||||
nohang = True
|
nohang = True
|
||||||
|
|
||||||
@requires_alpn
|
|
||||||
def test_http2(self):
|
def test_http2(self):
|
||||||
r, _ = self.pathoc(["GET:/"], ssl=True, use_http2=True)
|
r, _ = self.pathoc(["GET:/"], ssl=True, use_http2=True)
|
||||||
assert r[0].status_code == 800
|
assert r[0].status_code == 800
|
||||||
|
|
||||||
def test_no_http2(self, disable_alpn):
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
r, _ = self.pathoc(["GET:/"], ssl=True, use_http2=True)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user