Version 0.2.14
This commit is contained in:
parent
76d20774a5
commit
cbc0b4be4c
8 changed files with 942 additions and 393 deletions
|
@ -1455,6 +1455,8 @@ Changelog
|
||||||
---------
|
---------
|
||||||
The boring part of the readme
|
The boring part of the readme
|
||||||
|
|
||||||
|
* 0.2.14
|
||||||
|
* Critical bugfixes
|
||||||
* 0.2.13
|
* 0.2.13
|
||||||
* Refactor proxy core
|
* Refactor proxy core
|
||||||
* WEBSOCKETS
|
* WEBSOCKETS
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = '0.2.13'
|
__version__ = '0.2.14'
|
||||||
|
|
|
@ -3387,7 +3387,12 @@ class HTTPProtocolProxy(ProtocolProxy):
|
||||||
self.conn_is_ssl != use_ssl:
|
self.conn_is_ssl != use_ssl:
|
||||||
self.log("Closing connection to old server")
|
self.log("Closing connection to old server")
|
||||||
self.close_server_connection()
|
self.close_server_connection()
|
||||||
self.connect(host, port, use_ssl, use_socks=use_socks)
|
# we don't use SSL because maybe_use_ssl takes care of setting
|
||||||
|
# it up if we end up using it
|
||||||
|
if self.conn_is_maybe_ssl:
|
||||||
|
self.connect(host, port, False, use_socks=use_socks)
|
||||||
|
else:
|
||||||
|
self.connect(host, port, use_ssl, use_socks=use_socks)
|
||||||
|
|
||||||
def server_connection_lost(self, reason):
|
def server_connection_lost(self, reason):
|
||||||
self.log("Connection to server lost: %s" % str(reason))
|
self.log("Connection to server lost: %s" % str(reason))
|
||||||
|
|
|
@ -436,6 +436,73 @@ class MacroTemplate(object):
|
||||||
def template_argstring(cls, template):
|
def template_argstring(cls, template):
|
||||||
return cls._template_data[template][2]
|
return cls._template_data[template][2]
|
||||||
|
|
||||||
|
## Other functions
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def async_mangle_ws(self, request, message):
|
||||||
|
if hasattr(self.source, 'async_mangle_ws'):
|
||||||
|
mangled_ws = yield self.source.async_mangle_ws(request, message)
|
||||||
|
defer.returnValue(mangled_ws)
|
||||||
|
defer.returnValue(message)
|
||||||
|
|
||||||
|
class MacroTemplate(object):
|
||||||
|
_template_data = {
|
||||||
|
'macro': ('macro.py.template',
|
||||||
|
'Generic macro template',
|
||||||
|
'[reqids]',
|
||||||
|
'macro_{fname}.py',
|
||||||
|
gen_template_args_macro),
|
||||||
|
|
||||||
|
'intmacro': ('intmacro.py.template',
|
||||||
|
'Generic intercepting macro template',
|
||||||
|
'',
|
||||||
|
'int_{fname}.py',
|
||||||
|
gen_template_generator_noargs('intmacro')),
|
||||||
|
|
||||||
|
'modheader': ('macro_header.py.template',
|
||||||
|
'Modify a header in the request and the response if it exists.',
|
||||||
|
'',
|
||||||
|
'int_{fname}.py',
|
||||||
|
gen_template_generator_noargs('modheader')),
|
||||||
|
|
||||||
|
'resubmit': ('macro_resubmit.py.template',
|
||||||
|
'Resubmit all in-context requests',
|
||||||
|
'',
|
||||||
|
'macro_{fname}.py',
|
||||||
|
gen_template_generator_noargs('resubmit')),
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fill_template(cls, template, subs):
|
||||||
|
loader = FileSystemLoader(session.config.pappy_dir+'/templates')
|
||||||
|
env = Environment(loader=loader)
|
||||||
|
template = env.get_template(cls._template_data[template][0])
|
||||||
|
return template.render(zip=zip, **subs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def fill_template_args(cls, template, args=[]):
|
||||||
|
ret = cls._template_data[template][4](args)
|
||||||
|
if isinstance(ret, defer.Deferred):
|
||||||
|
ret = yield ret
|
||||||
|
defer.returnValue(ret)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def template_filename(cls, template, fname):
|
||||||
|
return cls._template_data[template][3].format(fname=fname)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def template_list(cls):
|
||||||
|
return [k for k, v in cls._template_data.iteritems()]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def template_description(cls, template):
|
||||||
|
return cls._template_data[template][1]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def template_argstring(cls, template):
|
||||||
|
return cls._template_data[template][2]
|
||||||
|
|
||||||
## Other functions
|
## Other functions
|
||||||
|
|
||||||
def load_macros(loc):
|
def load_macros(loc):
|
||||||
|
|
|
@ -307,17 +307,20 @@ class ProtocolProxy(object):
|
||||||
self.client_connected = False
|
self.client_connected = False
|
||||||
self.client_buffer = ''
|
self.client_buffer = ''
|
||||||
self.client_start_tls = False
|
self.client_start_tls = False
|
||||||
|
self.client_tls_host = ''
|
||||||
self.client_protocol = None
|
self.client_protocol = None
|
||||||
|
self.client_do_maybe_tls = False
|
||||||
|
|
||||||
self.server_transport = None
|
self.server_transport = None
|
||||||
self.server_connected = False
|
self.server_connected = False
|
||||||
self.server_buffer = ''
|
self.server_buffer = ''
|
||||||
self.server_start_tls = False
|
self.server_start_tls = False
|
||||||
|
self.conn_is_maybe_ssl = False
|
||||||
self.server_protocol = None
|
self.server_protocol = None
|
||||||
|
|
||||||
self.conn_host = None
|
self.conn_host = None
|
||||||
self.conn_port = None
|
self.conn_port = None
|
||||||
self.conn_is_ssl = None
|
self.conn_is_ssl = False
|
||||||
self.connection_id = get_next_connection_id()
|
self.connection_id = get_next_connection_id()
|
||||||
|
|
||||||
def log(self, message, symbol='*', verbosity_level=3):
|
def log(self, message, symbol='*', verbosity_level=3):
|
||||||
|
@ -330,23 +333,37 @@ class ProtocolProxy(object):
|
||||||
from pappyproxy.pappy import session
|
from pappyproxy.pappy import session
|
||||||
|
|
||||||
self.connecting = True
|
self.connecting = True
|
||||||
self.log("Connecting to %s:%d ssl=%s" % (host, port, use_ssl))
|
|
||||||
|
connect_with_ssl = use_ssl
|
||||||
|
if self.conn_is_maybe_ssl:
|
||||||
|
connect_with_ssl = False
|
||||||
|
|
||||||
|
self.log("Connecting to %s:%d ssl=%s (maybe_ssl=%s)" % (host, port, connect_with_ssl, self.conn_is_maybe_ssl))
|
||||||
factory = PassthroughProtocolFactory(self.server_data_received,
|
factory = PassthroughProtocolFactory(self.server_data_received,
|
||||||
self.server_connection_made,
|
self.server_connection_made,
|
||||||
self.server_connection_lost)
|
self.server_connection_lost)
|
||||||
self.conn_host = host
|
self.conn_host = host
|
||||||
self.conn_port = port
|
self.conn_port = port
|
||||||
self.conn_is_ssl = use_ssl
|
if self.conn_is_maybe_ssl:
|
||||||
|
self.conn_is_ssl = False
|
||||||
|
else:
|
||||||
|
self.conn_is_ssl = use_ssl
|
||||||
if use_socks:
|
if use_socks:
|
||||||
socks_config = session.config.socks_proxy
|
socks_config = session.config.socks_proxy
|
||||||
else:
|
else:
|
||||||
socks_config = None
|
socks_config = None
|
||||||
|
|
||||||
make_proxied_connection(factory, host, port, use_ssl, socks_config=socks_config,
|
make_proxied_connection(factory, host, port, connect_with_ssl, socks_config=socks_config,
|
||||||
log_id=self.connection_id, http_error_transport=self.client_transport)
|
log_id=self.connection_id, http_error_transport=self.client_transport)
|
||||||
|
|
||||||
## Client interactions
|
## Client interactions
|
||||||
|
|
||||||
|
def client_data_received(self, data):
|
||||||
|
"""
|
||||||
|
Implemented by child class
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
def send_client_data(self, data):
|
def send_client_data(self, data):
|
||||||
self.log("pc< %s" % short_data(data))
|
self.log("pc< %s" % short_data(data))
|
||||||
if self.client_connected:
|
if self.client_connected:
|
||||||
|
@ -355,12 +372,17 @@ class ProtocolProxy(object):
|
||||||
self.client_buffer += data
|
self.client_buffer += data
|
||||||
|
|
||||||
def client_connection_made(self, protocol):
|
def client_connection_made(self, protocol):
|
||||||
|
self.log("Client connection made")
|
||||||
|
self.client_protocol = protocol
|
||||||
self.client_transport = self.client_protocol.transport
|
self.client_transport = self.client_protocol.transport
|
||||||
self.client_connected = True
|
self.client_connected = True
|
||||||
self.connecting = False
|
self.connecting = False
|
||||||
|
|
||||||
if self.client_start_tls:
|
if self.client_start_tls:
|
||||||
self.start_client_tls()
|
if self.client_do_maybe_tls:
|
||||||
|
self.start_client_maybe_tls(self.client_tls_host)
|
||||||
|
else:
|
||||||
|
self.start_client_tls(self.client_tls_host)
|
||||||
if self.client_buffer != '':
|
if self.client_buffer != '':
|
||||||
self.client_transport.write(self.client_buffer)
|
self.client_transport.write(self.client_buffer)
|
||||||
self.client_buffer = ''
|
self.client_buffer = ''
|
||||||
|
@ -377,16 +399,25 @@ class ProtocolProxy(object):
|
||||||
def start_server_tls(self):
|
def start_server_tls(self):
|
||||||
if self.server_connected:
|
if self.server_connected:
|
||||||
self.log("Starting TLS on server transport")
|
self.log("Starting TLS on server transport")
|
||||||
|
self.conn_is_ssl = True
|
||||||
self.server_transport.startTLS(ssl.ClientContextFactory())
|
self.server_transport.startTLS(ssl.ClientContextFactory())
|
||||||
else:
|
else:
|
||||||
self.log("Server not yet connected, will start TLS on connect")
|
self.log("Server not yet connected, will start TLS on connect")
|
||||||
self.start_server_tls = True
|
self.server_start_tls = True
|
||||||
|
|
||||||
def start_client_maybe_tls(self, cert_host):
|
def start_client_maybe_tls(self, cert_host):
|
||||||
ctx = generate_tls_context(cert_host)
|
ctx = generate_tls_context(cert_host)
|
||||||
start_maybe_tls(self.client_transport,
|
if self.client_connected:
|
||||||
tls_host=cert_host,
|
self.log("Starting maybe TLS on client transport")
|
||||||
start_tls_callback=self.start_server_tls)
|
self.conn_is_maybe_ssl = True
|
||||||
|
start_maybe_tls(self.client_transport,
|
||||||
|
tls_host=cert_host,
|
||||||
|
start_tls_callback=self.start_server_tls)
|
||||||
|
else:
|
||||||
|
self.log("Client not yet connected, will start maybe TLS on connect")
|
||||||
|
self.client_do_maybe_tls = True
|
||||||
|
self.client_start_tls = True
|
||||||
|
self.client_tls_host = cert_host
|
||||||
|
|
||||||
def start_client_tls(self, cert_host):
|
def start_client_tls(self, cert_host):
|
||||||
if self.client_connected:
|
if self.client_connected:
|
||||||
|
@ -395,10 +426,17 @@ class ProtocolProxy(object):
|
||||||
self.client_transport.startTLS(ctx)
|
self.client_transport.startTLS(ctx)
|
||||||
else:
|
else:
|
||||||
self.log("Client not yet connected, will start TLS on connect")
|
self.log("Client not yet connected, will start TLS on connect")
|
||||||
self.start_client_tls = True
|
self.client_start_tls = True
|
||||||
|
self.client_tls_host = cert_host
|
||||||
|
|
||||||
## Server interactions
|
## Server interactions
|
||||||
|
|
||||||
|
def server_data_received(self, data):
|
||||||
|
"""
|
||||||
|
Implemented by child class
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
def send_server_data(self, data):
|
def send_server_data(self, data):
|
||||||
if self.server_connected:
|
if self.server_connected:
|
||||||
self.log("ps> %s" % short_data(data))
|
self.log("ps> %s" % short_data(data))
|
||||||
|
@ -412,7 +450,7 @@ class ProtocolProxy(object):
|
||||||
"""
|
"""
|
||||||
self.server_protocol must be set before calling
|
self.server_protocol must be set before calling
|
||||||
"""
|
"""
|
||||||
self.log("Connection made")
|
self.log("Server connection made")
|
||||||
self.server_protocol = protocol
|
self.server_protocol = protocol
|
||||||
self.server_transport = protocol.transport
|
self.server_transport = protocol.transport
|
||||||
self.server_connected = True
|
self.server_connected = True
|
||||||
|
@ -441,6 +479,7 @@ class ProtocolProxy(object):
|
||||||
self.server_transport = None
|
self.server_transport = None
|
||||||
self.server_connected = False
|
self.server_connected = False
|
||||||
self.server_buffer = ''
|
self.server_buffer = ''
|
||||||
|
self.server_start_tls = False
|
||||||
self.server_protocol = None
|
self.server_protocol = None
|
||||||
|
|
||||||
def close_client_connection(self):
|
def close_client_connection(self):
|
||||||
|
@ -450,7 +489,10 @@ class ProtocolProxy(object):
|
||||||
self.client_transport = None
|
self.client_transport = None
|
||||||
self.client_connected = False
|
self.client_connected = False
|
||||||
self.client_buffer = ''
|
self.client_buffer = ''
|
||||||
|
self.client_start_tls = False
|
||||||
|
self.client_tls_host = ''
|
||||||
self.client_protocol = None
|
self.client_protocol = None
|
||||||
|
self.client_do_maybe_tls = False
|
||||||
|
|
||||||
def close_connections(self):
|
def close_connections(self):
|
||||||
self.close_server_connection()
|
self.close_server_connection()
|
||||||
|
|
421
pappyproxy/tests/test_http_proxy.py
Normal file
421
pappyproxy/tests/test_http_proxy.py
Normal file
|
@ -0,0 +1,421 @@
|
||||||
|
import pytest
|
||||||
|
import mock
|
||||||
|
import random
|
||||||
|
import datetime
|
||||||
|
import pappyproxy
|
||||||
|
import base64
|
||||||
|
import collections
|
||||||
|
|
||||||
|
from pappyproxy import http
|
||||||
|
from pappyproxy.proxy import ProxyClientFactory, ProxyServerFactory, UpstreamHTTPProxyClient
|
||||||
|
from pappyproxy.http import Request, Response
|
||||||
|
from pappyproxy.macros import InterceptMacro
|
||||||
|
from testutil import mock_deferred, func_deleted, TLSStringTransport, freeze, mock_int_macro, no_tcp
|
||||||
|
from twisted.internet import defer
|
||||||
|
|
||||||
|
class InterceptMacroTest(InterceptMacro):
|
||||||
|
|
||||||
|
def __init__(self, new_req=None, new_rsp=None):
|
||||||
|
InterceptMacro.__init__(self)
|
||||||
|
|
||||||
|
self.new_req = None
|
||||||
|
self.new_rsp = None
|
||||||
|
if new_req:
|
||||||
|
self.intercept_requests = True
|
||||||
|
self.new_req = new_req
|
||||||
|
if new_rsp:
|
||||||
|
self.intercept_responses = True
|
||||||
|
self.new_rsp = new_rsp
|
||||||
|
|
||||||
|
def mangle_request(self, request):
|
||||||
|
if self.intercept_requests:
|
||||||
|
return self.new_req
|
||||||
|
else:
|
||||||
|
return request
|
||||||
|
|
||||||
|
def mangle_response(self, request):
|
||||||
|
if self.intercept_responses:
|
||||||
|
return self.new_rsp
|
||||||
|
else:
|
||||||
|
return request.response
|
||||||
|
|
||||||
|
class TestProxyConnection(object):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client_protocol(self):
|
||||||
|
if 'protocol' not in self.conn_info:
|
||||||
|
raise Exception('Connection to server not made. Cannot write data as server.')
|
||||||
|
return self.conn_info['protocol']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client_factory(self):
|
||||||
|
if 'protocol' not in self.conn_info:
|
||||||
|
raise Exception('Connection to server not made. Cannot write data as server.')
|
||||||
|
return self.conn_info['factory']
|
||||||
|
|
||||||
|
def setUp(self, mocker, int_macros={}, socks_config=None, http_config=None, in_scope=True):
|
||||||
|
self.mocker = mocker
|
||||||
|
self.conn_info = {}
|
||||||
|
|
||||||
|
# Mock config
|
||||||
|
self.mock_config = pappyproxy.config.PappyConfig()
|
||||||
|
self.mock_config.socks_proxy = socks_config
|
||||||
|
self.mock_config.http_proxy = http_config
|
||||||
|
self.mock_session = pappyproxy.pappy.PappySession(self.mock_config)
|
||||||
|
mocker.patch.object(pappyproxy.pappy, 'session', new=self.mock_session)
|
||||||
|
mocker.patch("pappyproxy.proxy.load_certs_from_dir", new=mock_generate_cert)
|
||||||
|
|
||||||
|
# Listening server
|
||||||
|
## self.server_factory = ProxyServerFactory()
|
||||||
|
## self.server_factory.save_all = True
|
||||||
|
## self.server_factory.intercepting_macros = int_macros
|
||||||
|
## self.server_protocol = self.server_factory.buildProtocol(('127.0.0.1', 0))
|
||||||
|
## self.server_transport = TLSStringTransport()
|
||||||
|
## self.server_protocol.makeConnection(self.server_transport)
|
||||||
|
|
||||||
|
# Other mocks
|
||||||
|
self.req_save = mocker.patch.object(pappyproxy.http.Request, 'async_deep_save', autospec=True, side_effect=mock_req_async_save)
|
||||||
|
self.submit_request = mocker.patch('pappyproxy.http.Request.submit_request',
|
||||||
|
new=self.gen_mock_submit_request())
|
||||||
|
self.make_proxied_connection = mocker.patch('pappyproxy.proxy.make_proxied_connection')
|
||||||
|
self.in_scope = mocker.patch('pappyproxy.context.in_scope').return_value = in_scope
|
||||||
|
|
||||||
|
def gen_mock_submit_request(self):
|
||||||
|
orig = Request.submit_request
|
||||||
|
def f(request, save_request=False, intercepting_macros={}, stream_transport=None):
|
||||||
|
return orig(request, save_request=save_request,
|
||||||
|
intercepting_macros=intercepting_macros,
|
||||||
|
stream_transport=stream_transport,
|
||||||
|
_factory_string_transport=True,
|
||||||
|
_conn_info=self.conn_info)
|
||||||
|
return f
|
||||||
|
|
||||||
|
def perform_connect_request(self):
|
||||||
|
self.write_as_browser('CONNECT https://www.AAAA.BBBB:443 HTTP/1.1\r\n\r\n')
|
||||||
|
assert self.read_as_browser() == 'HTTP/1.1 200 Connection established\r\n\r\n'
|
||||||
|
|
||||||
|
def write_as_browser(self, data):
|
||||||
|
self.server_protocol.dataReceived(data)
|
||||||
|
|
||||||
|
def read_as_browser(self):
|
||||||
|
s = self.server_protocol.transport.value()
|
||||||
|
self.server_protocol.transport.clear()
|
||||||
|
return s
|
||||||
|
|
||||||
|
def write_as_server(self, data):
|
||||||
|
self.client_protocol.dataReceived(data)
|
||||||
|
|
||||||
|
def read_as_server(self):
|
||||||
|
s = self.client_protocol.transport.value()
|
||||||
|
self.client_protocol.transport.clear()
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def mock_req_async_save(req):
|
||||||
|
req.reqid = str(random.randint(1,1000000))
|
||||||
|
return mock_deferred()
|
||||||
|
|
||||||
|
def mock_mangle_response_side_effect(new_rsp):
|
||||||
|
def f(request, mangle_macros):
|
||||||
|
request.response = new_rsp
|
||||||
|
return mock_deferred(True)
|
||||||
|
return f
|
||||||
|
|
||||||
|
def mock_generate_cert(cert_dir):
|
||||||
|
private_key = ('-----BEGIN PRIVATE KEY-----\n'
|
||||||
|
'MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDAoClrYUEB7lM0\n'
|
||||||
|
'zQaKkXZVG2d1Bu9hV8urpx0gNXMbyZ2m3xb+sKZju/FHPuWenA4KaN5gRUT+oLfv\n'
|
||||||
|
'tnF6Ia0jpRNWnX0Fyn/irdg1BWGJn7k7mJ2D0NXZQczn2+xxY05599NfGWqNKCYy\n'
|
||||||
|
'jhSwPsUK+sGJqi7aSDdlS97ZTjrQVTTFsC0+kSu4lS5fsWXxqrKLa6Ao8W7abVRO\n'
|
||||||
|
'JHazh/cxM4UKpgWU+E6yD4o4ZgHY+SMTVUh/IOM8DuOVyLEWtx4oLNiLMlpWT3qy\n'
|
||||||
|
'4IMpOF6VuU6JF2HGV13SoJfhsLXsPRbLVTAnZvJcZwtgDm6NfKapU8W8olkDV1Bf\n'
|
||||||
|
'YQEMSNX7AgMBAAECggEBAII0wUrAdrzjaIMsg9tu8FofKBPHGFDok9f4Iov/FUwX\n'
|
||||||
|
'QOXnrxeCOTb5d+L89SH9ws/ui0LwD+8+nJcA8DvqP6r0jtnhov0jIMcNVDSi6oeo\n'
|
||||||
|
'3AEY7ICJzcQJ4oRn+K+8vPNdPhfuikPYe9l4iSuJgpAlaGWyD/GlFyz12DFz2/Wu\n'
|
||||||
|
'NIcqR1ucvezRHn3eGMtvDv2WGaN4ifUc30k8XgSUesmwSI6beb5+hxq7wXfsurnP\n'
|
||||||
|
'EUrPY9ts3lfiAgxzTKOuj1VR5hn7cJyLN8jF0mZs4D6eSSHorIddhmaNiCq5ZbMd\n'
|
||||||
|
'QdlDiPvnXHT41OoXOb7tDEt7SGoiRh2noCZ1aZiSziECgYEA+tuPPLYWU6JRB6EW\n'
|
||||||
|
'PhbcXQbh3vML7eT1q7DOz0jYCojgT2+k7EWSI8T830oQyjbpe3Z86XEgH7UBjUgq\n'
|
||||||
|
'27nJ4E6dQDYGbYCKEklOoCGLE7A60i1feIz8otOQRrbQ4jcpibEgscA6gzHmunYf\n'
|
||||||
|
'De5euUgYW+Rq2Vmr6/NzUaUgui8CgYEAxJMDwPOGgiLM1cczlaSIU9Obz+cVnwWn\n'
|
||||||
|
'nsdKYMto2V3yKLydDfjsgOgzxHOxxy+5L645TPxK6CkiISuhJ93kAFFtx+1sCBCT\n'
|
||||||
|
'tVzY5robVAekxA9tlPIxtsn3+/axx3n6HnV0oA/XtxkuOS5JImgEdXqFwJZkerGE\n'
|
||||||
|
'waftIU2FCfUCgYEArl8+ErJzlJEIiCgWIPSdGuD00pfZW/TCPCT7rKRy3+fDHBR7\n'
|
||||||
|
'7Gxzp/9+0utV/mnrJBH5w/8JmGCmgoF+oRtk01FyBzdGgolN8GYajD6kwPvH917o\n'
|
||||||
|
'tRAzcC9lY3IigoxbiEWid0wqoBVoz4XaEkH2gA44OG/vQcQOOEYSi9cfh6sCgYBg\n'
|
||||||
|
'KLaOXdJvuIxRCzgNvMW/k+VFh3pJJx//COg2f2qT4mQCT3nYiutOh8hDEoFluc+y\n'
|
||||||
|
'Jlz7bvNJrE14wnn8IYxWJ383bMoLC+jlsDyeaW3S5kZQbmehk/SDwTrg86W1udKD\n'
|
||||||
|
'sdtSLU3N0LCO4jh+bzm3Ki9hrXALoOkbPoU+ZEhvPQKBgQDf79XQ3RNxZSk+eFyq\n'
|
||||||
|
'qD8ytVqxEoD+smPDflXXseVH6o+pNWrF8+A0KqmO8c+8KVzWj/OfULO6UbKd3E+x\n'
|
||||||
|
'4JGkWu9yF1lEgtHgibF2ER8zCSIL4ikOEasPCkrKj5SrS4Q+j4u5ha76dIc2CVu1\n'
|
||||||
|
'hkX2PQ1xU4ocu06k373sf73A4Q==\n'
|
||||||
|
'-----END PRIVATE KEY-----')
|
||||||
|
ca_key = ('-----BEGIN CERTIFICATE-----\n'
|
||||||
|
'MIIDjzCCAncCFQCjC8r+I4xa7JoGUJYGOTcqDROA0DANBgkqhkiG9w0BAQsFADBg\n'
|
||||||
|
'MQswCQYDVQQGEwJVUzERMA8GA1UECBMITWljaGlnYW4xEjAQBgNVBAcTCUFubiBB\n'
|
||||||
|
'cmJvcjEUMBIGA1UEChMLUGFwcHkgUHJveHkxFDASBgNVBAMTC1BhcHB5IFByb3h5\n'
|
||||||
|
'MB4XDTE1MTEyMDIxMTEzOVoXDTI1MTExNzIxMTEzOVowYDELMAkGA1UEBhMCVVMx\n'
|
||||||
|
'ETAPBgNVBAgTCE1pY2hpZ2FuMRIwEAYDVQQHEwlBbm4gQXJib3IxFDASBgNVBAoT\n'
|
||||||
|
'C1BhcHB5IFByb3h5MRQwEgYDVQQDEwtQYXBweSBQcm94eTCCASIwDQYJKoZIhvcN\n'
|
||||||
|
'AQEBBQADggEPADCCAQoCggEBAMCgKWthQQHuUzTNBoqRdlUbZ3UG72FXy6unHSA1\n'
|
||||||
|
'cxvJnabfFv6wpmO78Uc+5Z6cDgpo3mBFRP6gt++2cXohrSOlE1adfQXKf+Kt2DUF\n'
|
||||||
|
'YYmfuTuYnYPQ1dlBzOfb7HFjTnn3018Zao0oJjKOFLA+xQr6wYmqLtpIN2VL3tlO\n'
|
||||||
|
'OtBVNMWwLT6RK7iVLl+xZfGqsotroCjxbtptVE4kdrOH9zEzhQqmBZT4TrIPijhm\n'
|
||||||
|
'Adj5IxNVSH8g4zwO45XIsRa3Higs2IsyWlZPerLggyk4XpW5TokXYcZXXdKgl+Gw\n'
|
||||||
|
'tew9FstVMCdm8lxnC2AObo18pqlTxbyiWQNXUF9hAQxI1fsCAwEAAaNFMEMwEgYD\n'
|
||||||
|
'VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNo5o+5e\n'
|
||||||
|
'a0sNMlW/75VgGJCv2AcJMA0GCSqGSIb3DQEBCwUAA4IBAQBdJDhxbmoEe27bD8me\n'
|
||||||
|
'YTcLGjs/StKkSil7rLbX+tBCwtkm5UEEejBuAhKk2FuAXW8yR1FqKJSZwVCAocBT\n'
|
||||||
|
'Bo/+97Ee+h7ywrRFhATEr9D/TbbHKOjCjDzOMl9yLZa2DKErZjbI30ZD6NafWS/X\n'
|
||||||
|
'hx5X1cGohHcVVzT4jIgUEU70vvYfNn8CTZm4oJ7qqRe/uQPUYy0rwvbd60oprtGg\n'
|
||||||
|
'jNv1H5R4ODHUMBXAI9H7ft9cWrd0fBQjxhoj8pvgJXEZ52flXSqQc7qHLg1wO/zC\n'
|
||||||
|
'RUgpTcNAb2qCssBKbj+c1vKEPRUJfw6UYb0s1462rQNc8BgZiKaNbwokFmkAnjUg\n'
|
||||||
|
'AvnX\n'
|
||||||
|
'-----END CERTIFICATE-----')
|
||||||
|
return (ca_key, private_key)
|
||||||
|
|
||||||
|
########
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
def test_no_tcp():
|
||||||
|
from twisted.internet.endpoints import SSL4ClientEndpoint, TCP4ClientEndpoint
|
||||||
|
from txsocksx.client import SOCKS5ClientEndpoint
|
||||||
|
from txsocksx.tls import TLSWrapClientEndpoint
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
SSL4ClientEndpoint('aasdfasdf.sdfwerqwer')
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
TCP4ClientEndpoint('aasdfasdf.sdfwerqwer')
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
SOCKS5ClientEndpoint('aasdfasdf.sdfwerqwer')
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
TLSWrapClientEndpoint('asdf.2341')
|
||||||
|
|
||||||
|
def test_proxy_server_connect(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
proxy.setUp(mocker)
|
||||||
|
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:443 HTTP/1.1\r\n\r\n')
|
||||||
|
rsp = proxy.read_as_browser()
|
||||||
|
print rsp
|
||||||
|
assert rsp == 'HTTP/1.1 200 Connection established\r\n\r\n'
|
||||||
|
|
||||||
|
def test_proxy_server_forward_basic(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
proxy.setUp(mocker)
|
||||||
|
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
||||||
|
'Test-Header: foo\r\n'
|
||||||
|
'Content-Length: 4\r\n'
|
||||||
|
'Host: www.AAAA.BBBB\r\n'
|
||||||
|
'\r\n'
|
||||||
|
'ABCD')
|
||||||
|
rsp_contents = ('HTTP/1.1 200 OK\r\n\r\n')
|
||||||
|
proxy.write_as_browser(req_contents)
|
||||||
|
assert proxy.read_as_server() == req_contents
|
||||||
|
proxy.write_as_server(rsp_contents)
|
||||||
|
assert proxy.read_as_browser() == rsp_contents
|
||||||
|
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80, False, socks_config=None, use_http_proxy=True)
|
||||||
|
assert proxy.req_save.called
|
||||||
|
|
||||||
|
def test_proxy_server_forward_basic_ssl(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
proxy.setUp(mocker)
|
||||||
|
proxy.perform_connect_request()
|
||||||
|
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
||||||
|
'Test-Header: foo\r\n'
|
||||||
|
'Content-Length: 4\r\n'
|
||||||
|
'\r\n'
|
||||||
|
'ABCD')
|
||||||
|
rsp_contents = ('HTTP/1.1 200 OK\r\n\r\n')
|
||||||
|
proxy.write_as_browser(req_contents)
|
||||||
|
assert proxy.read_as_server() == req_contents
|
||||||
|
proxy.write_as_server(rsp_contents)
|
||||||
|
assert proxy.read_as_browser() == rsp_contents
|
||||||
|
assert proxy.req_save.called
|
||||||
|
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 443, True, socks_config=None, use_http_proxy=True)
|
||||||
|
|
||||||
|
def test_proxy_server_connect_uri(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
proxy.setUp(mocker)
|
||||||
|
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:443 HTTP/1.1\r\n\r\n')
|
||||||
|
proxy.read_as_browser()
|
||||||
|
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
||||||
|
'Test-Header: foo\r\n'
|
||||||
|
'Content-Length: 4\r\n'
|
||||||
|
'\r\n'
|
||||||
|
'ABCD')
|
||||||
|
proxy.write_as_browser(req_contents)
|
||||||
|
assert proxy.client_protocol.transport.startTLS.called
|
||||||
|
assert proxy.client_factory.request.host == 'www.AAAA.BBBB'
|
||||||
|
assert proxy.client_factory.request.port == 443
|
||||||
|
assert proxy.client_factory.request.is_ssl == True
|
||||||
|
assert proxy.read_as_server() == req_contents
|
||||||
|
assert proxy.client_protocol.transport.startTLS.called
|
||||||
|
assert proxy.req_save.called
|
||||||
|
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 443, True, socks_config=None, use_http_proxy=True)
|
||||||
|
|
||||||
|
def test_proxy_server_connect_uri_alt_port(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
proxy.setUp(mocker)
|
||||||
|
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:80085 HTTP/1.1\r\n\r\n')
|
||||||
|
proxy.read_as_browser()
|
||||||
|
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
||||||
|
'Test-Header: foo\r\n'
|
||||||
|
'Content-Length: 4\r\n'
|
||||||
|
'\r\n'
|
||||||
|
'ABCD')
|
||||||
|
proxy.write_as_browser(req_contents)
|
||||||
|
assert proxy.client_factory.request.host == 'www.AAAA.BBBB'
|
||||||
|
assert proxy.client_factory.request.port == 80085
|
||||||
|
assert proxy.client_factory.request.is_ssl == True
|
||||||
|
assert proxy.req_save.called
|
||||||
|
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80085, True, socks_config=None, use_http_proxy=True)
|
||||||
|
|
||||||
|
def test_proxy_server_socks_basic(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
proxy.setUp(mocker, socks_config={'host': 'www.banana.faketld', 'port': 1337})
|
||||||
|
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:80085 HTTP/1.1\r\n\r\n')
|
||||||
|
proxy.read_as_browser()
|
||||||
|
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
||||||
|
'Test-Header: foo\r\n'
|
||||||
|
'Content-Length: 4\r\n'
|
||||||
|
'\r\n'
|
||||||
|
'ABCD')
|
||||||
|
proxy.write_as_browser(req_contents)
|
||||||
|
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80085, True,
|
||||||
|
socks_config={'host':'www.banana.faketld', 'port':1337},
|
||||||
|
use_http_proxy=True)
|
||||||
|
|
||||||
|
def test_proxy_server_http_basic(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
proxy.setUp(mocker, http_config={'host': 'www.banana.faketld', 'port': 1337})
|
||||||
|
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:80085 HTTP/1.1\r\n\r\n')
|
||||||
|
proxy.read_as_browser()
|
||||||
|
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
||||||
|
'Test-Header: foo\r\n'
|
||||||
|
'Content-Length: 4\r\n'
|
||||||
|
'\r\n'
|
||||||
|
'ABCD')
|
||||||
|
proxy.write_as_browser(req_contents)
|
||||||
|
assert proxy.req_save.called
|
||||||
|
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80085, True,
|
||||||
|
socks_config=None,
|
||||||
|
use_http_proxy=True)
|
||||||
|
|
||||||
|
def test_proxy_server_360_noscope(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
proxy.setUp(mocker, in_scope=False, socks_config={'host': 'www.banana.faketld', 'port': 1337})
|
||||||
|
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:80085 HTTP/1.1\r\n\r\n')
|
||||||
|
proxy.read_as_browser()
|
||||||
|
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
||||||
|
'Test-Header: foo\r\n'
|
||||||
|
'Content-Length: 4\r\n'
|
||||||
|
'\r\n'
|
||||||
|
'ABCD')
|
||||||
|
proxy.write_as_browser(req_contents)
|
||||||
|
assert not proxy.req_save.called
|
||||||
|
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80085, True,
|
||||||
|
socks_config=None,
|
||||||
|
use_http_proxy=False)
|
||||||
|
|
||||||
|
def test_proxy_server_macro_simple(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
|
||||||
|
new_req_contents = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
new_rsp_contents = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
new_req = Request(new_req_contents)
|
||||||
|
new_rsp = Response(new_rsp_contents)
|
||||||
|
test_macro = InterceptMacroTest(new_req=new_req, new_rsp=new_rsp)
|
||||||
|
proxy.setUp(mocker, int_macros={'test_macro': test_macro})
|
||||||
|
proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
||||||
|
assert proxy.read_as_server() == new_req_contents
|
||||||
|
proxy.write_as_server('HTTP/1.1 404 NOT FOUND\r\n\r\n')
|
||||||
|
assert proxy.read_as_browser() == new_rsp_contents
|
||||||
|
|
||||||
|
def test_proxy_server_macro_multiple(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
|
||||||
|
new_req_contents1 = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
new_rsp_contents1 = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
new_req1 = Request(new_req_contents1)
|
||||||
|
new_rsp1 = Response(new_rsp_contents1)
|
||||||
|
|
||||||
|
new_req_contents2 = 'GET / HTTP/1.1\r\nMangled: Very very yes\r\n\r\n'
|
||||||
|
new_rsp_contents2 = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very very yes\r\n\r\n'
|
||||||
|
new_req2 = Request(new_req_contents2)
|
||||||
|
new_rsp2 = Response(new_rsp_contents2)
|
||||||
|
|
||||||
|
test_macro1 = InterceptMacroTest(new_req=new_req1, new_rsp=new_rsp1)
|
||||||
|
test_macro2 = InterceptMacroTest(new_req=new_req2, new_rsp=new_rsp2)
|
||||||
|
|
||||||
|
macros = collections.OrderedDict()
|
||||||
|
macros['macro1'] = test_macro1
|
||||||
|
macros['macro2'] = test_macro2
|
||||||
|
|
||||||
|
proxy.setUp(mocker, int_macros=macros)
|
||||||
|
proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
||||||
|
assert proxy.read_as_server() == new_req_contents2
|
||||||
|
proxy.write_as_server('HTTP/1.1 404 NOT FOUND\r\n\r\n')
|
||||||
|
assert proxy.read_as_browser() == new_rsp_contents2
|
||||||
|
|
||||||
|
def test_proxy_server_macro_360_noscope(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
|
||||||
|
new_req_contents = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
new_rsp_contents = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
new_req = Request(new_req_contents)
|
||||||
|
new_rsp = Response(new_rsp_contents)
|
||||||
|
test_macro = InterceptMacroTest(new_req=new_req, new_rsp=new_rsp)
|
||||||
|
proxy.setUp(mocker, int_macros={'test_macro': test_macro}, in_scope=False)
|
||||||
|
proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
||||||
|
assert proxy.read_as_server() == 'GET /serious.php HTTP/1.1\r\n\r\n'
|
||||||
|
proxy.write_as_server('HTTP/1.1 404 NOT FOUND\r\n\r\n')
|
||||||
|
assert proxy.read_as_browser() == 'HTTP/1.1 404 NOT FOUND\r\n\r\n'
|
||||||
|
|
||||||
|
def test_proxy_server_stream_simple(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
proxy.setUp(mocker)
|
||||||
|
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
||||||
|
'Test-Header: foo\r\n'
|
||||||
|
'Content-Length: 4\r\n'
|
||||||
|
'Host: www.AAAA.BBBB\r\n'
|
||||||
|
'\r\n'
|
||||||
|
'ABCD')
|
||||||
|
rsp_contents = ('HTTP/1.1 200 OK\r\n\r\n')
|
||||||
|
proxy.write_as_browser(req_contents)
|
||||||
|
assert proxy.read_as_server() == req_contents
|
||||||
|
proxy.write_as_server(rsp_contents[:20])
|
||||||
|
assert proxy.read_as_browser() == rsp_contents[:20]
|
||||||
|
proxy.write_as_server(rsp_contents[20:])
|
||||||
|
assert proxy.read_as_browser() == rsp_contents[20:]
|
||||||
|
|
||||||
|
def test_proxy_server_macro_stream(mocker):
|
||||||
|
proxy = TestProxyConnection()
|
||||||
|
|
||||||
|
new_req_contents = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
new_rsp_contents = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
new_req = Request(new_req_contents)
|
||||||
|
new_rsp = Response(new_rsp_contents)
|
||||||
|
test_macro = InterceptMacroTest(new_req=new_req, new_rsp=new_rsp)
|
||||||
|
proxy.setUp(mocker, int_macros={'test_macro': test_macro})
|
||||||
|
proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
||||||
|
assert proxy.read_as_server() == new_req_contents
|
||||||
|
proxy.write_as_server('HTTP/1.1 404 ')
|
||||||
|
assert proxy.read_as_browser() == ''
|
||||||
|
proxy.write_as_server('NOT FOUND\r\n\r\n')
|
||||||
|
assert proxy.read_as_browser() == new_rsp_contents
|
||||||
|
|
||||||
|
# It doesn't stream if out of scope and macros are active, but whatever.
|
||||||
|
# def test_proxy_server_macro_stream_360_noscope(mocker):
|
||||||
|
# proxy = TestProxyConnection()
|
||||||
|
|
||||||
|
# new_req_contents = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
# new_rsp_contents = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
||||||
|
# new_req = Request(new_req_contents)
|
||||||
|
# new_rsp = Response(new_rsp_contents)
|
||||||
|
# test_macro = InterceptMacroTest(new_req=new_req, new_rsp=new_rsp)
|
||||||
|
# proxy.setUp(mocker, int_macros={'test_macro': test_macro}, in_scope=False)
|
||||||
|
# proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
||||||
|
# assert proxy.read_as_server() == 'GET /serious.php HTTP/1.1\r\n\r\n'
|
||||||
|
# proxy.write_as_server('HTTP/1.1 404 ')
|
||||||
|
# assert proxy.read_as_browser() == 'HTTP/1.1 404 '
|
||||||
|
# proxy.write_as_server('NOT FOUND\r\n\r\n')
|
||||||
|
# assert proxy.read_as_browser() == 'NOT FOUND\r\n\r\n'
|
|
@ -1,422 +1,370 @@
|
||||||
import pytest
|
|
||||||
import mock
|
import mock
|
||||||
import random
|
import pytest
|
||||||
import datetime
|
import twisted.internet.endpoints
|
||||||
import pappyproxy
|
|
||||||
import base64
|
|
||||||
import collections
|
|
||||||
|
|
||||||
from pappyproxy import http
|
from pappyproxy import http
|
||||||
from pappyproxy.proxy import ProxyClientFactory, ProxyServerFactory, UpstreamHTTPProxyClient
|
from pappyproxy.proxy import MaybeTLSProtocol, start_maybe_tls, PassthroughProtocolFactory, make_proxied_connection
|
||||||
from pappyproxy.http import Request, Response
|
from testutil import mock_deferred, func_deleted, TLSStringTransport, freeze, mock_int_macro, no_tcp, mock_config
|
||||||
from pappyproxy.macros import InterceptMacro
|
from pappyproxy.util import PappyStringTransport
|
||||||
from testutil import mock_deferred, func_deleted, TLSStringTransport, freeze, mock_int_macro, no_tcp
|
from twisted.internet import defer, ssl
|
||||||
from twisted.internet import defer
|
|
||||||
|
|
||||||
class InterceptMacroTest(InterceptMacro):
|
###############################
|
||||||
|
## Helper functions and classes
|
||||||
|
|
||||||
def __init__(self, new_req=None, new_rsp=None):
|
def gen_debug_protocol(mocker):
|
||||||
InterceptMacro.__init__(self)
|
def fake_start_tls(transport, context):
|
||||||
|
transport.protocol = mock.MagicMock()
|
||||||
|
mocker.patch("pappyproxy.util.PappyStringTransport.startTLS", new=fake_start_tls)
|
||||||
|
mocker.patch("pappyproxy.proxy.generate_tls_context")
|
||||||
|
|
||||||
self.new_req = None
|
t = PappyStringTransport()
|
||||||
self.new_rsp = None
|
def server_data_received(s):
|
||||||
if new_req:
|
t.write(s)
|
||||||
self.intercept_requests = True
|
factory = PassthroughProtocolFactory(server_data_received, None, None)
|
||||||
self.new_req = new_req
|
p = factory.buildProtocol(None)
|
||||||
if new_rsp:
|
p.transport = t
|
||||||
self.intercept_responses = True
|
t.protocol= p
|
||||||
self.new_rsp = new_rsp
|
return p, t
|
||||||
|
|
||||||
def mangle_request(self, request):
|
def mock_protocol_proxy(mocker):
|
||||||
if self.intercept_requests:
|
from pappyproxy import proxy
|
||||||
return self.new_req
|
mock_make_proxied_connection = mocker.patch("pappyproxy.proxy.make_proxied_connection")
|
||||||
else:
|
p = proxy.ProtocolProxy()
|
||||||
return request
|
p.client_transport = PappyStringTransport()
|
||||||
|
p.server_transport = PappyStringTransport()
|
||||||
|
|
||||||
def mangle_response(self, request):
|
client_protocol, _ = gen_debug_protocol(mocker)
|
||||||
if self.intercept_responses:
|
server_protocol, _ = gen_debug_protocol(mocker)
|
||||||
return self.new_rsp
|
|
||||||
else:
|
|
||||||
return request.response
|
|
||||||
|
|
||||||
class TestProxyConnection(object):
|
return p, client_protocol, server_protocol, mock_make_proxied_connection
|
||||||
|
|
||||||
@property
|
##########################
|
||||||
def client_protocol(self):
|
## Tests for ProtocolProxy
|
||||||
if 'protocol' not in self.conn_info:
|
|
||||||
raise Exception('Connection to server not made. Cannot write data as server.')
|
|
||||||
return self.conn_info['protocol']
|
|
||||||
|
|
||||||
@property
|
def test_simple(mocker):
|
||||||
def client_factory(self):
|
mock_config(mocker)
|
||||||
if 'protocol' not in self.conn_info:
|
proxy, _, _, _ = mock_protocol_proxy(mocker)
|
||||||
raise Exception('Connection to server not made. Cannot write data as server.')
|
proxy.send_client_data("foobar")
|
||||||
return self.conn_info['factory']
|
assert proxy.client_buffer == "foobar"
|
||||||
|
proxy.send_server_data("barfoo")
|
||||||
|
assert proxy.server_buffer == "barfoo"
|
||||||
|
|
||||||
|
def test_connect(mocker):
|
||||||
|
mock_config(mocker)
|
||||||
|
proxy, _, _, mock_make_proxied_connection = mock_protocol_proxy(mocker)
|
||||||
|
proxy.send_client_data("foobar")
|
||||||
|
proxy.send_server_data("barfoo")
|
||||||
|
proxy.connect("fakehost", 1337, False)
|
||||||
|
assert len(mock_make_proxied_connection.mock_calls) == 1
|
||||||
|
callargs = mock_make_proxied_connection.mock_calls[0][1]
|
||||||
|
assert callargs[1] == "fakehost"
|
||||||
|
assert callargs[2] == 1337
|
||||||
|
assert callargs[3] == False
|
||||||
|
|
||||||
def setUp(self, mocker, int_macros={}, socks_config=None, http_config=None, in_scope=True):
|
def test_send_before_connect(mocker):
|
||||||
self.mocker = mocker
|
mock_config(mocker)
|
||||||
self.conn_info = {}
|
proxy, client_protocol, server_protocol, mock_make_proxied_connection = mock_protocol_proxy(mocker)
|
||||||
|
proxy.send_client_data("foobar")
|
||||||
|
proxy.send_server_data("barfoo")
|
||||||
|
|
||||||
# Mock config
|
proxy.connect("fakehost", 1337, False)
|
||||||
self.mock_config = pappyproxy.config.PappyConfig()
|
|
||||||
self.mock_config.socks_proxy = socks_config
|
|
||||||
self.mock_config.http_proxy = http_config
|
|
||||||
self.mock_session = pappyproxy.pappy.PappySession(self.mock_config)
|
|
||||||
mocker.patch.object(pappyproxy.pappy, 'session', new=self.mock_session)
|
|
||||||
mocker.patch("pappyproxy.proxy.load_certs_from_dir", new=mock_generate_cert)
|
|
||||||
|
|
||||||
# Listening server
|
proxy.client_connection_made(client_protocol)
|
||||||
self.server_factory = ProxyServerFactory()
|
assert proxy.client_buffer == ''
|
||||||
self.server_factory.save_all = True
|
assert client_protocol.transport.pop_value() == 'foobar'
|
||||||
self.server_factory.intercepting_macros = int_macros
|
|
||||||
|
|
||||||
self.server_protocol = self.server_factory.buildProtocol(('127.0.0.1', 0))
|
assert proxy.server_buffer == 'barfoo'
|
||||||
self.server_transport = TLSStringTransport()
|
|
||||||
self.server_protocol.makeConnection(self.server_transport)
|
|
||||||
|
|
||||||
# Other mocks
|
proxy.server_connection_made(server_protocol)
|
||||||
self.req_save = mocker.patch.object(pappyproxy.http.Request, 'async_deep_save', autospec=True, side_effect=mock_req_async_save)
|
assert proxy.server_buffer == ''
|
||||||
self.submit_request = mocker.patch('pappyproxy.http.Request.submit_request',
|
assert server_protocol.transport.pop_value() == 'barfoo'
|
||||||
new=self.gen_mock_submit_request())
|
|
||||||
self.get_endpoint = mocker.patch('pappyproxy.proxy.get_endpoint')
|
|
||||||
self.in_scope = mocker.patch('pappyproxy.context.in_scope').return_value = in_scope
|
|
||||||
|
|
||||||
def gen_mock_submit_request(self):
|
def test_send_after_connect(mocker):
|
||||||
orig = Request.submit_request
|
mock_config(mocker)
|
||||||
def f(request, save_request=False, intercepting_macros={}, stream_transport=None):
|
proxy, client_protocol, server_protocol, mock_make_proxied_connection = mock_protocol_proxy(mocker)
|
||||||
return orig(request, save_request=save_request,
|
|
||||||
intercepting_macros=intercepting_macros,
|
proxy.connect("fakehost", 1337, False)
|
||||||
stream_transport=stream_transport,
|
|
||||||
_factory_string_transport=True,
|
proxy.client_connection_made(client_protocol)
|
||||||
_conn_info=self.conn_info)
|
proxy.send_client_data("foobar")
|
||||||
return f
|
assert client_protocol.transport.pop_value() == 'foobar'
|
||||||
|
|
||||||
|
proxy.server_connection_made(server_protocol)
|
||||||
|
proxy.send_server_data("barfoo")
|
||||||
|
assert server_protocol.transport.pop_value() == 'barfoo'
|
||||||
|
|
||||||
def perform_connect_request(self):
|
def test_start_tls_before_connect(mocker):
|
||||||
self.write_as_browser('CONNECT https://www.AAAA.BBBB:443 HTTP/1.1\r\n\r\n')
|
mock_config(mocker)
|
||||||
assert self.read_as_browser() == 'HTTP/1.1 200 Connection established\r\n\r\n'
|
proxy, client_protocol, server_protocol, mock_make_proxied_connection = mock_protocol_proxy(mocker)
|
||||||
|
client_protocol.transport.startTLS = mock.MagicMock()
|
||||||
|
server_protocol.transport.startTLS = mock.MagicMock()
|
||||||
|
|
||||||
def write_as_browser(self, data):
|
server_protocol.transport.startTLS.assert_not_called()
|
||||||
self.server_protocol.dataReceived(data)
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
proxy.start_server_tls()
|
||||||
|
proxy.start_client_tls("fakehost")
|
||||||
|
|
||||||
def read_as_browser(self):
|
server_protocol.transport.startTLS.assert_not_called()
|
||||||
s = self.server_protocol.transport.value()
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
self.server_protocol.transport.clear()
|
proxy.connect("fakehost", 1337, False)
|
||||||
return s
|
server_protocol.transport.startTLS.assert_not_called()
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
|
||||||
def write_as_server(self, data):
|
proxy.server_connection_made(server_protocol)
|
||||||
self.client_protocol.dataReceived(data)
|
assert len(server_protocol.transport.startTLS.mock_calls) == 1
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
|
||||||
def read_as_server(self):
|
proxy.client_connection_made(client_protocol)
|
||||||
s = self.client_protocol.transport.value()
|
assert len(client_protocol.transport.startTLS.mock_calls) == 1
|
||||||
self.client_protocol.transport.clear()
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
def test_start_tls_after_connect(mocker):
|
||||||
|
mock_config(mocker)
|
||||||
|
proxy, client_protocol, server_protocol, mock_make_proxied_connection = mock_protocol_proxy(mocker)
|
||||||
|
client_protocol.transport.startTLS = mock.MagicMock()
|
||||||
|
server_protocol.transport.startTLS = mock.MagicMock()
|
||||||
|
|
||||||
|
server_protocol.transport.startTLS.assert_not_called()
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
|
||||||
|
proxy.connect("fakehost", 1337, False)
|
||||||
|
|
||||||
|
server_protocol.transport.startTLS.assert_not_called()
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
|
||||||
|
proxy.server_connection_made(server_protocol)
|
||||||
|
proxy.start_server_tls()
|
||||||
|
assert len(server_protocol.transport.startTLS.mock_calls) == 1
|
||||||
|
|
||||||
|
proxy.client_connection_made(client_protocol)
|
||||||
|
proxy.start_client_tls("fakehost")
|
||||||
|
assert len(client_protocol.transport.startTLS.mock_calls) == 1
|
||||||
|
|
||||||
|
def test_start_maybe_tls_before_connect(mocker):
|
||||||
|
mock_config(mocker)
|
||||||
|
proxy, client_protocol, server_protocol, mock_make_proxied_connection = mock_protocol_proxy(mocker)
|
||||||
|
mock_maybe_tls = mocker.patch("pappyproxy.proxy.start_maybe_tls")
|
||||||
|
client_protocol.transport.startTLS = mock.MagicMock()
|
||||||
|
server_protocol.transport.startTLS = mock.MagicMock()
|
||||||
|
|
||||||
|
proxy.start_client_maybe_tls("fakehost")
|
||||||
|
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
proxy.connect("fakehost", 1337, False)
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
|
||||||
|
proxy.client_connection_made(client_protocol)
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
assert len(mock_maybe_tls.mock_calls) == 1
|
||||||
|
|
||||||
|
callargs = mock_maybe_tls.mock_calls[0][2]
|
||||||
|
assert callargs['tls_host'] == 'fakehost'
|
||||||
|
assert callargs['start_tls_callback'] == proxy.start_server_tls
|
||||||
|
|
||||||
|
def test_start_maybe_tls_before_connect(mocker):
|
||||||
|
mock_config(mocker)
|
||||||
|
proxy, client_protocol, server_protocol, mock_make_proxied_connection = mock_protocol_proxy(mocker)
|
||||||
|
mock_maybe_tls = mocker.patch("pappyproxy.proxy.start_maybe_tls")
|
||||||
|
client_protocol.transport.startTLS = mock.MagicMock()
|
||||||
|
server_protocol.transport.startTLS = mock.MagicMock()
|
||||||
|
|
||||||
|
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
proxy.connect("fakehost", 1337, False)
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
|
||||||
|
proxy.client_connection_made(client_protocol)
|
||||||
|
proxy.start_client_maybe_tls("fakehost")
|
||||||
|
client_protocol.transport.startTLS.assert_not_called()
|
||||||
|
assert len(mock_maybe_tls.mock_calls) == 1
|
||||||
|
|
||||||
|
callargs = mock_maybe_tls.mock_calls[0][2]
|
||||||
|
assert callargs['tls_host'] == 'fakehost'
|
||||||
|
assert callargs['start_tls_callback'] == proxy.start_server_tls
|
||||||
|
|
||||||
def mock_req_async_save(req):
|
|
||||||
req.reqid = str(random.randint(1,1000000))
|
|
||||||
return mock_deferred()
|
|
||||||
|
|
||||||
def mock_mangle_response_side_effect(new_rsp):
|
#############################
|
||||||
def f(request, mangle_macros):
|
## Tests for MaybeTLSProtocol
|
||||||
request.response = new_rsp
|
def test_maybe_tls_plaintext(mocker):
|
||||||
return mock_deferred(True)
|
mock_config(mocker)
|
||||||
return f
|
tls_callback = mock.MagicMock()
|
||||||
|
p, t = gen_debug_protocol(mocker)
|
||||||
|
start_maybe_tls(p.transport, 'www.foo.faketld')
|
||||||
|
p.dataReceived("Hello world!")
|
||||||
|
assert p.transport.pop_value() == "Hello world!"
|
||||||
|
|
||||||
def mock_generate_cert(cert_dir):
|
def test_maybe_tls_use_tls(mocker):
|
||||||
private_key = ('-----BEGIN PRIVATE KEY-----\n'
|
mock_config(mocker)
|
||||||
'MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDAoClrYUEB7lM0\n'
|
tls_callback = mock.MagicMock()
|
||||||
'zQaKkXZVG2d1Bu9hV8urpx0gNXMbyZ2m3xb+sKZju/FHPuWenA4KaN5gRUT+oLfv\n'
|
p, t = gen_debug_protocol(mocker)
|
||||||
'tnF6Ia0jpRNWnX0Fyn/irdg1BWGJn7k7mJ2D0NXZQczn2+xxY05599NfGWqNKCYy\n'
|
start_maybe_tls(p.transport, 'www.foo.faketld')
|
||||||
'jhSwPsUK+sGJqi7aSDdlS97ZTjrQVTTFsC0+kSu4lS5fsWXxqrKLa6Ao8W7abVRO\n'
|
maybe_tls_prot = t.protocol
|
||||||
'JHazh/cxM4UKpgWU+E6yD4o4ZgHY+SMTVUh/IOM8DuOVyLEWtx4oLNiLMlpWT3qy\n'
|
assert isinstance(maybe_tls_prot, MaybeTLSProtocol)
|
||||||
'4IMpOF6VuU6JF2HGV13SoJfhsLXsPRbLVTAnZvJcZwtgDm6NfKapU8W8olkDV1Bf\n'
|
assert maybe_tls_prot.state == MaybeTLSProtocol.STATE_DECIDING
|
||||||
'YQEMSNX7AgMBAAECggEBAII0wUrAdrzjaIMsg9tu8FofKBPHGFDok9f4Iov/FUwX\n'
|
t.protocol.dataReceived("\x16")
|
||||||
'QOXnrxeCOTb5d+L89SH9ws/ui0LwD+8+nJcA8DvqP6r0jtnhov0jIMcNVDSi6oeo\n'
|
assert not isinstance(t.protocol, MaybeTLSProtocol)
|
||||||
'3AEY7ICJzcQJ4oRn+K+8vPNdPhfuikPYe9l4iSuJgpAlaGWyD/GlFyz12DFz2/Wu\n'
|
assert maybe_tls_prot.state == MaybeTLSProtocol.STATE_PASSTHROUGH
|
||||||
'NIcqR1ucvezRHn3eGMtvDv2WGaN4ifUc30k8XgSUesmwSI6beb5+hxq7wXfsurnP\n'
|
|
||||||
'EUrPY9ts3lfiAgxzTKOuj1VR5hn7cJyLN8jF0mZs4D6eSSHorIddhmaNiCq5ZbMd\n'
|
|
||||||
'QdlDiPvnXHT41OoXOb7tDEt7SGoiRh2noCZ1aZiSziECgYEA+tuPPLYWU6JRB6EW\n'
|
|
||||||
'PhbcXQbh3vML7eT1q7DOz0jYCojgT2+k7EWSI8T830oQyjbpe3Z86XEgH7UBjUgq\n'
|
|
||||||
'27nJ4E6dQDYGbYCKEklOoCGLE7A60i1feIz8otOQRrbQ4jcpibEgscA6gzHmunYf\n'
|
|
||||||
'De5euUgYW+Rq2Vmr6/NzUaUgui8CgYEAxJMDwPOGgiLM1cczlaSIU9Obz+cVnwWn\n'
|
|
||||||
'nsdKYMto2V3yKLydDfjsgOgzxHOxxy+5L645TPxK6CkiISuhJ93kAFFtx+1sCBCT\n'
|
|
||||||
'tVzY5robVAekxA9tlPIxtsn3+/axx3n6HnV0oA/XtxkuOS5JImgEdXqFwJZkerGE\n'
|
|
||||||
'waftIU2FCfUCgYEArl8+ErJzlJEIiCgWIPSdGuD00pfZW/TCPCT7rKRy3+fDHBR7\n'
|
|
||||||
'7Gxzp/9+0utV/mnrJBH5w/8JmGCmgoF+oRtk01FyBzdGgolN8GYajD6kwPvH917o\n'
|
|
||||||
'tRAzcC9lY3IigoxbiEWid0wqoBVoz4XaEkH2gA44OG/vQcQOOEYSi9cfh6sCgYBg\n'
|
|
||||||
'KLaOXdJvuIxRCzgNvMW/k+VFh3pJJx//COg2f2qT4mQCT3nYiutOh8hDEoFluc+y\n'
|
|
||||||
'Jlz7bvNJrE14wnn8IYxWJ383bMoLC+jlsDyeaW3S5kZQbmehk/SDwTrg86W1udKD\n'
|
|
||||||
'sdtSLU3N0LCO4jh+bzm3Ki9hrXALoOkbPoU+ZEhvPQKBgQDf79XQ3RNxZSk+eFyq\n'
|
|
||||||
'qD8ytVqxEoD+smPDflXXseVH6o+pNWrF8+A0KqmO8c+8KVzWj/OfULO6UbKd3E+x\n'
|
|
||||||
'4JGkWu9yF1lEgtHgibF2ER8zCSIL4ikOEasPCkrKj5SrS4Q+j4u5ha76dIc2CVu1\n'
|
|
||||||
'hkX2PQ1xU4ocu06k373sf73A4Q==\n'
|
|
||||||
'-----END PRIVATE KEY-----')
|
|
||||||
ca_key = ('-----BEGIN CERTIFICATE-----\n'
|
|
||||||
'MIIDjzCCAncCFQCjC8r+I4xa7JoGUJYGOTcqDROA0DANBgkqhkiG9w0BAQsFADBg\n'
|
|
||||||
'MQswCQYDVQQGEwJVUzERMA8GA1UECBMITWljaGlnYW4xEjAQBgNVBAcTCUFubiBB\n'
|
|
||||||
'cmJvcjEUMBIGA1UEChMLUGFwcHkgUHJveHkxFDASBgNVBAMTC1BhcHB5IFByb3h5\n'
|
|
||||||
'MB4XDTE1MTEyMDIxMTEzOVoXDTI1MTExNzIxMTEzOVowYDELMAkGA1UEBhMCVVMx\n'
|
|
||||||
'ETAPBgNVBAgTCE1pY2hpZ2FuMRIwEAYDVQQHEwlBbm4gQXJib3IxFDASBgNVBAoT\n'
|
|
||||||
'C1BhcHB5IFByb3h5MRQwEgYDVQQDEwtQYXBweSBQcm94eTCCASIwDQYJKoZIhvcN\n'
|
|
||||||
'AQEBBQADggEPADCCAQoCggEBAMCgKWthQQHuUzTNBoqRdlUbZ3UG72FXy6unHSA1\n'
|
|
||||||
'cxvJnabfFv6wpmO78Uc+5Z6cDgpo3mBFRP6gt++2cXohrSOlE1adfQXKf+Kt2DUF\n'
|
|
||||||
'YYmfuTuYnYPQ1dlBzOfb7HFjTnn3018Zao0oJjKOFLA+xQr6wYmqLtpIN2VL3tlO\n'
|
|
||||||
'OtBVNMWwLT6RK7iVLl+xZfGqsotroCjxbtptVE4kdrOH9zEzhQqmBZT4TrIPijhm\n'
|
|
||||||
'Adj5IxNVSH8g4zwO45XIsRa3Higs2IsyWlZPerLggyk4XpW5TokXYcZXXdKgl+Gw\n'
|
|
||||||
'tew9FstVMCdm8lxnC2AObo18pqlTxbyiWQNXUF9hAQxI1fsCAwEAAaNFMEMwEgYD\n'
|
|
||||||
'VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNo5o+5e\n'
|
|
||||||
'a0sNMlW/75VgGJCv2AcJMA0GCSqGSIb3DQEBCwUAA4IBAQBdJDhxbmoEe27bD8me\n'
|
|
||||||
'YTcLGjs/StKkSil7rLbX+tBCwtkm5UEEejBuAhKk2FuAXW8yR1FqKJSZwVCAocBT\n'
|
|
||||||
'Bo/+97Ee+h7ywrRFhATEr9D/TbbHKOjCjDzOMl9yLZa2DKErZjbI30ZD6NafWS/X\n'
|
|
||||||
'hx5X1cGohHcVVzT4jIgUEU70vvYfNn8CTZm4oJ7qqRe/uQPUYy0rwvbd60oprtGg\n'
|
|
||||||
'jNv1H5R4ODHUMBXAI9H7ft9cWrd0fBQjxhoj8pvgJXEZ52flXSqQc7qHLg1wO/zC\n'
|
|
||||||
'RUgpTcNAb2qCssBKbj+c1vKEPRUJfw6UYb0s1462rQNc8BgZiKaNbwokFmkAnjUg\n'
|
|
||||||
'AvnX\n'
|
|
||||||
'-----END CERTIFICATE-----')
|
|
||||||
return (ca_key, private_key)
|
|
||||||
|
|
||||||
########
|
####################################
|
||||||
## Tests
|
## Tests for make_proxied_connection
|
||||||
|
def test_mpc_simple(mocker):
|
||||||
|
mock_config(mocker)
|
||||||
|
endpoint_instance = mock.MagicMock()
|
||||||
|
endpoint = mocker.patch('twisted.internet.endpoints.TCP4ClientEndpoint', return_value=endpoint_instance)
|
||||||
|
|
||||||
def test_no_tcp():
|
make_proxied_connection('fakefactory', 'fakehost', 1337, False)
|
||||||
from twisted.internet.endpoints import SSL4ClientEndpoint, TCP4ClientEndpoint
|
|
||||||
from txsocksx.client import SOCKS5ClientEndpoint
|
|
||||||
from txsocksx.tls import TLSWrapClientEndpoint
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
SSL4ClientEndpoint('aasdfasdf.sdfwerqwer')
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
TCP4ClientEndpoint('aasdfasdf.sdfwerqwer')
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
SOCKS5ClientEndpoint('aasdfasdf.sdfwerqwer')
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
TLSWrapClientEndpoint('asdf.2341')
|
|
||||||
|
|
||||||
def test_proxy_server_connect(mocker):
|
|
||||||
proxy = TestProxyConnection()
|
|
||||||
proxy.setUp(mocker)
|
|
||||||
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:443 HTTP/1.1\r\n\r\n')
|
|
||||||
rsp = proxy.read_as_browser()
|
|
||||||
print rsp
|
|
||||||
assert rsp == 'HTTP/1.1 200 Connection established\r\n\r\n'
|
|
||||||
|
|
||||||
def test_proxy_server_forward_basic(mocker):
|
endpointcalls = endpoint.mock_calls[0]
|
||||||
proxy = TestProxyConnection()
|
assert endpointcalls[1][1] == 'fakehost'
|
||||||
proxy.setUp(mocker)
|
assert endpointcalls[1][2] == 1337
|
||||||
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
|
||||||
'Test-Header: foo\r\n'
|
|
||||||
'Content-Length: 4\r\n'
|
|
||||||
'Host: www.AAAA.BBBB\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'ABCD')
|
|
||||||
rsp_contents = ('HTTP/1.1 200 OK\r\n\r\n')
|
|
||||||
proxy.write_as_browser(req_contents)
|
|
||||||
assert proxy.read_as_server() == req_contents
|
|
||||||
proxy.write_as_server(rsp_contents)
|
|
||||||
assert proxy.read_as_browser() == rsp_contents
|
|
||||||
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80, False, socks_config=None, use_http_proxy=True)
|
|
||||||
assert proxy.req_save.called
|
|
||||||
|
|
||||||
def test_proxy_server_forward_basic_ssl(mocker):
|
connectcall = endpoint_instance.connect
|
||||||
proxy = TestProxyConnection()
|
assert len(connectcall.mock_calls) == 1
|
||||||
proxy.setUp(mocker)
|
|
||||||
proxy.perform_connect_request()
|
|
||||||
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
|
||||||
'Test-Header: foo\r\n'
|
|
||||||
'Content-Length: 4\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'ABCD')
|
|
||||||
rsp_contents = ('HTTP/1.1 200 OK\r\n\r\n')
|
|
||||||
proxy.write_as_browser(req_contents)
|
|
||||||
assert proxy.read_as_server() == req_contents
|
|
||||||
proxy.write_as_server(rsp_contents)
|
|
||||||
assert proxy.read_as_browser() == rsp_contents
|
|
||||||
assert proxy.req_save.called
|
|
||||||
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 443, True, socks_config=None, use_http_proxy=True)
|
|
||||||
|
|
||||||
def test_proxy_server_connect_uri(mocker):
|
def test_mpc_ssl(mocker):
|
||||||
proxy = TestProxyConnection()
|
mock_config(mocker)
|
||||||
proxy.setUp(mocker)
|
endpoint_instance = mock.MagicMock()
|
||||||
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:443 HTTP/1.1\r\n\r\n')
|
endpoint = mocker.patch('twisted.internet.endpoints.SSL4ClientEndpoint', return_value=endpoint_instance)
|
||||||
proxy.read_as_browser()
|
|
||||||
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
|
||||||
'Test-Header: foo\r\n'
|
|
||||||
'Content-Length: 4\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'ABCD')
|
|
||||||
proxy.write_as_browser(req_contents)
|
|
||||||
assert proxy.client_protocol.transport.startTLS.called
|
|
||||||
assert proxy.client_factory.request.host == 'www.AAAA.BBBB'
|
|
||||||
assert proxy.client_factory.request.port == 443
|
|
||||||
assert proxy.client_factory.request.is_ssl == True
|
|
||||||
assert proxy.read_as_server() == req_contents
|
|
||||||
assert proxy.client_protocol.transport.startTLS.called
|
|
||||||
assert proxy.req_save.called
|
|
||||||
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 443, True, socks_config=None, use_http_proxy=True)
|
|
||||||
|
|
||||||
def test_proxy_server_connect_uri_alt_port(mocker):
|
make_proxied_connection('fakefactory', 'fakehost', 1337, True)
|
||||||
proxy = TestProxyConnection()
|
|
||||||
proxy.setUp(mocker)
|
|
||||||
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:80085 HTTP/1.1\r\n\r\n')
|
|
||||||
proxy.read_as_browser()
|
|
||||||
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
|
||||||
'Test-Header: foo\r\n'
|
|
||||||
'Content-Length: 4\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'ABCD')
|
|
||||||
proxy.write_as_browser(req_contents)
|
|
||||||
assert proxy.client_factory.request.host == 'www.AAAA.BBBB'
|
|
||||||
assert proxy.client_factory.request.port == 80085
|
|
||||||
assert proxy.client_factory.request.is_ssl == True
|
|
||||||
assert proxy.req_save.called
|
|
||||||
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80085, True, socks_config=None, use_http_proxy=True)
|
|
||||||
|
|
||||||
def test_proxy_server_socks_basic(mocker):
|
endpointcalls = endpoint.mock_calls[0]
|
||||||
proxy = TestProxyConnection()
|
assert endpointcalls[1][1] == 'fakehost'
|
||||||
proxy.setUp(mocker, socks_config={'host': 'www.banana.faketld', 'port': 1337})
|
assert endpointcalls[1][2] == 1337
|
||||||
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:80085 HTTP/1.1\r\n\r\n')
|
assert isinstance(endpointcalls[1][3], ssl.ClientContextFactory)
|
||||||
proxy.read_as_browser()
|
|
||||||
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
|
||||||
'Test-Header: foo\r\n'
|
|
||||||
'Content-Length: 4\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'ABCD')
|
|
||||||
proxy.write_as_browser(req_contents)
|
|
||||||
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80085, True,
|
|
||||||
socks_config={'host':'www.banana.faketld', 'port':1337},
|
|
||||||
use_http_proxy=True)
|
|
||||||
|
|
||||||
def test_proxy_server_http_basic(mocker):
|
connectcall = endpoint_instance.connect
|
||||||
proxy = TestProxyConnection()
|
assert len(connectcall.mock_calls) == 1
|
||||||
proxy.setUp(mocker, http_config={'host': 'www.banana.faketld', 'port': 1337})
|
|
||||||
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:80085 HTTP/1.1\r\n\r\n')
|
|
||||||
proxy.read_as_browser()
|
|
||||||
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
|
||||||
'Test-Header: foo\r\n'
|
|
||||||
'Content-Length: 4\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'ABCD')
|
|
||||||
proxy.write_as_browser(req_contents)
|
|
||||||
assert proxy.req_save.called
|
|
||||||
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80085, True,
|
|
||||||
socks_config=None,
|
|
||||||
use_http_proxy=True)
|
|
||||||
|
|
||||||
def test_proxy_server_360_noscope(mocker):
|
def test_mpc_socks(mocker):
|
||||||
proxy = TestProxyConnection()
|
mock_config(mocker)
|
||||||
proxy.setUp(mocker, in_scope=False, socks_config={'host': 'www.banana.faketld', 'port': 1337})
|
tcp_endpoint_instance = mock.MagicMock()
|
||||||
proxy.write_as_browser('CONNECT https://www.AAAA.BBBB:80085 HTTP/1.1\r\n\r\n')
|
socks_endpoint_instance = mock.MagicMock()
|
||||||
proxy.read_as_browser()
|
tcp_endpoint = mocker.patch('twisted.internet.endpoints.TCP4ClientEndpoint', return_value=tcp_endpoint_instance)
|
||||||
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
socks_endpoint = mocker.patch('txsocksx.client.SOCKS5ClientEndpoint', return_value=socks_endpoint_instance)
|
||||||
'Test-Header: foo\r\n'
|
|
||||||
'Content-Length: 4\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'ABCD')
|
|
||||||
proxy.write_as_browser(req_contents)
|
|
||||||
assert not proxy.req_save.called
|
|
||||||
proxy.get_endpoint.assert_called_with('www.AAAA.BBBB', 80085, True,
|
|
||||||
socks_config=None,
|
|
||||||
use_http_proxy=False)
|
|
||||||
|
|
||||||
def test_proxy_server_macro_simple(mocker):
|
|
||||||
proxy = TestProxyConnection()
|
|
||||||
|
|
||||||
new_req_contents = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
target_host = 'fakehost'
|
||||||
new_rsp_contents = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
target_port = 1337
|
||||||
new_req = Request(new_req_contents)
|
|
||||||
new_rsp = Response(new_rsp_contents)
|
|
||||||
test_macro = InterceptMacroTest(new_req=new_req, new_rsp=new_rsp)
|
|
||||||
proxy.setUp(mocker, int_macros={'test_macro': test_macro})
|
|
||||||
proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
|
||||||
assert proxy.read_as_server() == new_req_contents
|
|
||||||
proxy.write_as_server('HTTP/1.1 404 NOT FOUND\r\n\r\n')
|
|
||||||
assert proxy.read_as_browser() == new_rsp_contents
|
|
||||||
|
|
||||||
def test_proxy_server_macro_multiple(mocker):
|
socks_host = 'fakesockshost'
|
||||||
proxy = TestProxyConnection()
|
socks_port = 1447
|
||||||
|
socks_config = {'host':socks_host, 'port':socks_port}
|
||||||
|
|
||||||
new_req_contents1 = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
make_proxied_connection('fakefactory', target_host, target_port, False, socks_config=socks_config)
|
||||||
new_rsp_contents1 = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
|
||||||
new_req1 = Request(new_req_contents1)
|
|
||||||
new_rsp1 = Response(new_rsp_contents1)
|
|
||||||
|
|
||||||
new_req_contents2 = 'GET / HTTP/1.1\r\nMangled: Very very yes\r\n\r\n'
|
tcp_ep_calls = tcp_endpoint.mock_calls[0]
|
||||||
new_rsp_contents2 = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very very yes\r\n\r\n'
|
assert tcp_ep_calls[1][1] == socks_host
|
||||||
new_req2 = Request(new_req_contents2)
|
assert tcp_ep_calls[1][2] == socks_port
|
||||||
new_rsp2 = Response(new_rsp_contents2)
|
|
||||||
|
|
||||||
test_macro1 = InterceptMacroTest(new_req=new_req1, new_rsp=new_rsp1)
|
socks_ep_calls = socks_endpoint.mock_calls[0]
|
||||||
test_macro2 = InterceptMacroTest(new_req=new_req2, new_rsp=new_rsp2)
|
assert socks_ep_calls[1][0] == target_host
|
||||||
|
assert socks_ep_calls[1][1] == target_port
|
||||||
|
assert socks_ep_calls[1][2] is tcp_endpoint_instance
|
||||||
|
assert socks_ep_calls[2]['methods'] == {'anonymous': ()}
|
||||||
|
|
||||||
macros = collections.OrderedDict()
|
connectcall = socks_endpoint_instance.connect
|
||||||
macros['macro1'] = test_macro1
|
assert len(connectcall.mock_calls) == 1
|
||||||
macros['macro2'] = test_macro2
|
|
||||||
|
|
||||||
proxy.setUp(mocker, int_macros=macros)
|
def test_mpc_socks_creds(mocker):
|
||||||
proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
mock_config(mocker)
|
||||||
assert proxy.read_as_server() == new_req_contents2
|
tcp_endpoint_instance = mock.MagicMock()
|
||||||
proxy.write_as_server('HTTP/1.1 404 NOT FOUND\r\n\r\n')
|
socks_endpoint_instance = mock.MagicMock()
|
||||||
assert proxy.read_as_browser() == new_rsp_contents2
|
tcp_endpoint = mocker.patch('twisted.internet.endpoints.TCP4ClientEndpoint', return_value=tcp_endpoint_instance)
|
||||||
|
socks_endpoint = mocker.patch('txsocksx.client.SOCKS5ClientEndpoint', return_value=socks_endpoint_instance)
|
||||||
|
|
||||||
def test_proxy_server_macro_360_noscope(mocker):
|
target_host = 'fakehost'
|
||||||
proxy = TestProxyConnection()
|
target_port = 1337
|
||||||
|
|
||||||
new_req_contents = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
socks_host = 'fakesockshost'
|
||||||
new_rsp_contents = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
socks_port = 1447
|
||||||
new_req = Request(new_req_contents)
|
socks_user = 'username'
|
||||||
new_rsp = Response(new_rsp_contents)
|
socks_password = 'password'
|
||||||
test_macro = InterceptMacroTest(new_req=new_req, new_rsp=new_rsp)
|
socks_config = {'host':socks_host, 'port':socks_port,
|
||||||
proxy.setUp(mocker, int_macros={'test_macro': test_macro}, in_scope=False)
|
'username':socks_user, 'password':socks_password}
|
||||||
proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
|
||||||
assert proxy.read_as_server() == 'GET /serious.php HTTP/1.1\r\n\r\n'
|
|
||||||
proxy.write_as_server('HTTP/1.1 404 NOT FOUND\r\n\r\n')
|
|
||||||
assert proxy.read_as_browser() == 'HTTP/1.1 404 NOT FOUND\r\n\r\n'
|
|
||||||
|
|
||||||
def test_proxy_server_stream_simple(mocker):
|
make_proxied_connection('fakefactory', target_host, target_port, False, socks_config=socks_config)
|
||||||
proxy = TestProxyConnection()
|
|
||||||
proxy.setUp(mocker)
|
|
||||||
req_contents = ('POST /fooo HTTP/1.1\r\n'
|
|
||||||
'Test-Header: foo\r\n'
|
|
||||||
'Content-Length: 4\r\n'
|
|
||||||
'Host: www.AAAA.BBBB\r\n'
|
|
||||||
'\r\n'
|
|
||||||
'ABCD')
|
|
||||||
rsp_contents = ('HTTP/1.1 200 OK\r\n\r\n')
|
|
||||||
proxy.write_as_browser(req_contents)
|
|
||||||
assert proxy.read_as_server() == req_contents
|
|
||||||
proxy.write_as_server(rsp_contents[:20])
|
|
||||||
assert proxy.read_as_browser() == rsp_contents[:20]
|
|
||||||
proxy.write_as_server(rsp_contents[20:])
|
|
||||||
assert proxy.read_as_browser() == rsp_contents[20:]
|
|
||||||
|
|
||||||
def test_proxy_server_macro_stream(mocker):
|
tcp_ep_calls = tcp_endpoint.mock_calls[0]
|
||||||
proxy = TestProxyConnection()
|
assert tcp_ep_calls[1][1] == socks_host
|
||||||
|
assert tcp_ep_calls[1][2] == socks_port
|
||||||
|
|
||||||
new_req_contents = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
socks_ep_calls = socks_endpoint.mock_calls[0]
|
||||||
new_rsp_contents = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
assert socks_ep_calls[1][0] == target_host
|
||||||
new_req = Request(new_req_contents)
|
assert socks_ep_calls[1][1] == target_port
|
||||||
new_rsp = Response(new_rsp_contents)
|
assert socks_ep_calls[1][2] is tcp_endpoint_instance
|
||||||
test_macro = InterceptMacroTest(new_req=new_req, new_rsp=new_rsp)
|
assert socks_ep_calls[2]['methods'] == {'login': (socks_user, socks_password), 'anonymous': ()}
|
||||||
proxy.setUp(mocker, int_macros={'test_macro': test_macro})
|
|
||||||
proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
|
||||||
assert proxy.read_as_server() == new_req_contents
|
|
||||||
proxy.write_as_server('HTTP/1.1 404 ')
|
|
||||||
assert proxy.read_as_browser() == ''
|
|
||||||
proxy.write_as_server('NOT FOUND\r\n\r\n')
|
|
||||||
assert proxy.read_as_browser() == new_rsp_contents
|
|
||||||
|
|
||||||
# It doesn't stream if out of scope and macros are active, but whatever.
|
connectcall = socks_endpoint_instance.connect
|
||||||
# def test_proxy_server_macro_stream_360_noscope(mocker):
|
assert len(connectcall.mock_calls) == 1
|
||||||
# proxy = TestProxyConnection()
|
|
||||||
|
|
||||||
# new_req_contents = 'GET / HTTP/1.1\r\nMangled: Very yes\r\n\r\n'
|
def test_mpc_socks_ssl(mocker):
|
||||||
# new_rsp_contents = 'HTTP/1.1 200 OKILIE DOKILIE\r\nMangled: Very yes\r\n\r\n'
|
mock_config(mocker)
|
||||||
# new_req = Request(new_req_contents)
|
tcp_endpoint_instance = mock.MagicMock()
|
||||||
# new_rsp = Response(new_rsp_contents)
|
socks_endpoint_instance = mock.MagicMock()
|
||||||
# test_macro = InterceptMacroTest(new_req=new_req, new_rsp=new_rsp)
|
wrapper_instance = mock.MagicMock()
|
||||||
# proxy.setUp(mocker, int_macros={'test_macro': test_macro}, in_scope=False)
|
tcp_endpoint = mocker.patch('twisted.internet.endpoints.TCP4ClientEndpoint', return_value=tcp_endpoint_instance)
|
||||||
# proxy.write_as_browser('GET /serious.php HTTP/1.1\r\n\r\n')
|
socks_endpoint = mocker.patch('txsocksx.client.SOCKS5ClientEndpoint', return_value=socks_endpoint_instance)
|
||||||
# assert proxy.read_as_server() == 'GET /serious.php HTTP/1.1\r\n\r\n'
|
wrapper_endpoint = mocker.patch('txsocksx.tls.TLSWrapClientEndpoint', return_value=wrapper_instance)
|
||||||
# proxy.write_as_server('HTTP/1.1 404 ')
|
|
||||||
# assert proxy.read_as_browser() == 'HTTP/1.1 404 '
|
target_host = 'fakehost'
|
||||||
# proxy.write_as_server('NOT FOUND\r\n\r\n')
|
target_port = 1337
|
||||||
# assert proxy.read_as_browser() == 'NOT FOUND\r\n\r\n'
|
|
||||||
|
socks_host = 'fakesockshost'
|
||||||
|
socks_port = 1447
|
||||||
|
socks_config = {'host':socks_host, 'port':socks_port}
|
||||||
|
|
||||||
|
make_proxied_connection('fakefactory', target_host, target_port, True, socks_config=socks_config)
|
||||||
|
|
||||||
|
tcp_ep_calls = tcp_endpoint.mock_calls[0]
|
||||||
|
assert tcp_ep_calls[1][1] == socks_host
|
||||||
|
assert tcp_ep_calls[1][2] == socks_port
|
||||||
|
|
||||||
|
socks_ep_calls = socks_endpoint.mock_calls[0]
|
||||||
|
assert socks_ep_calls[1][0] == target_host
|
||||||
|
assert socks_ep_calls[1][1] == target_port
|
||||||
|
assert socks_ep_calls[1][2] is tcp_endpoint_instance
|
||||||
|
assert socks_ep_calls[2]['methods'] == {'anonymous': ()}
|
||||||
|
|
||||||
|
wrapper_calls = wrapper_endpoint.mock_calls[0]
|
||||||
|
assert isinstance(wrapper_calls[1][0], ssl.ClientContextFactory)
|
||||||
|
assert wrapper_calls[1][1] is socks_endpoint_instance
|
||||||
|
|
||||||
|
connectcall = wrapper_instance.connect
|
||||||
|
assert len(connectcall.mock_calls) == 1
|
||||||
|
|
||||||
|
def test_mpc_socks_ssl_creds(mocker):
|
||||||
|
mock_config(mocker)
|
||||||
|
tcp_endpoint_instance = mock.MagicMock()
|
||||||
|
socks_endpoint_instance = mock.MagicMock()
|
||||||
|
wrapper_instance = mock.MagicMock()
|
||||||
|
tcp_endpoint = mocker.patch('twisted.internet.endpoints.TCP4ClientEndpoint', return_value=tcp_endpoint_instance)
|
||||||
|
socks_endpoint = mocker.patch('txsocksx.client.SOCKS5ClientEndpoint', return_value=socks_endpoint_instance)
|
||||||
|
wrapper_endpoint = mocker.patch('txsocksx.tls.TLSWrapClientEndpoint', return_value=wrapper_instance)
|
||||||
|
|
||||||
|
target_host = 'fakehost'
|
||||||
|
target_port = 1337
|
||||||
|
|
||||||
|
socks_host = 'fakesockshost'
|
||||||
|
socks_port = 1447
|
||||||
|
socks_user = 'username'
|
||||||
|
socks_password = 'password'
|
||||||
|
socks_config = {'host':socks_host, 'port':socks_port,
|
||||||
|
'username':socks_user, 'password':socks_password}
|
||||||
|
|
||||||
|
make_proxied_connection('fakefactory', target_host, target_port, True, socks_config=socks_config)
|
||||||
|
|
||||||
|
tcp_ep_calls = tcp_endpoint.mock_calls[0]
|
||||||
|
assert tcp_ep_calls[1][1] == socks_host
|
||||||
|
assert tcp_ep_calls[1][2] == socks_port
|
||||||
|
|
||||||
|
socks_ep_calls = socks_endpoint.mock_calls[0]
|
||||||
|
assert socks_ep_calls[1][0] == target_host
|
||||||
|
assert socks_ep_calls[1][1] == target_port
|
||||||
|
assert socks_ep_calls[1][2] is tcp_endpoint_instance
|
||||||
|
assert socks_ep_calls[2]['methods'] == {'login': (socks_user, socks_password), 'anonymous': ()}
|
||||||
|
|
||||||
|
wrapper_calls = wrapper_endpoint.mock_calls[0]
|
||||||
|
assert isinstance(wrapper_calls[1][0], ssl.ClientContextFactory)
|
||||||
|
assert wrapper_calls[1][1] is socks_endpoint_instance
|
||||||
|
|
||||||
|
connectcall = wrapper_instance.connect
|
||||||
|
assert len(connectcall.mock_calls) == 1
|
||||||
|
|
|
@ -4,7 +4,7 @@ import pytest
|
||||||
import StringIO
|
import StringIO
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from twisted.test.proto_helpers import StringTransport
|
from twisted.test.proto_helpers import StringTransport
|
||||||
from pappyproxy import http
|
from pappyproxy import http, config, pappy
|
||||||
|
|
||||||
next_mock_id = 0
|
next_mock_id = 0
|
||||||
|
|
||||||
|
@ -56,12 +56,13 @@ def mock_deferred(value=None):
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def no_tcp(mocker):
|
def no_tcp(mocker):
|
||||||
# Don't make tcp connections
|
# Don't make tcp connections
|
||||||
mocker.patch("twisted.internet.reactor.connectTCP", new=func_deleted)
|
#mocker.patch("twisted.internet.reactor.connectTCP", new=func_deleted)
|
||||||
mocker.patch("twisted.internet.reactor.connectSSL", new=func_deleted)
|
#mocker.patch("twisted.internet.reactor.connectSSL", new=func_deleted)
|
||||||
mocker.patch("twisted.internet.endpoints.SSL4ClientEndpoint", new=func_deleted)
|
#mocker.patch("twisted.internet.endpoints.SSL4ClientEndpoint", new=func_deleted)
|
||||||
mocker.patch("twisted.internet.endpoints.TCP4ClientEndpoint", new=func_deleted)
|
#mocker.patch("twisted.internet.endpoints.TCP4ClientEndpoint", new=func_deleted)
|
||||||
mocker.patch("txsocksx.client.SOCKS5ClientEndpoint", new=func_deleted)
|
#mocker.patch("txsocksx.client.SOCKS5ClientEndpoint", new=func_deleted)
|
||||||
mocker.patch("txsocksx.tls.TLSWrapClientEndpoint", new=func_deleted)
|
#mocker.patch("txsocksx.tls.TLSWrapClientEndpoint", new=func_deleted)
|
||||||
|
pass
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def ignore_tcp(mocker):
|
def ignore_tcp(mocker):
|
||||||
|
@ -170,3 +171,66 @@ def mock_int_macro(modified_req=None, modified_rsp=None,
|
||||||
else:
|
else:
|
||||||
macro.intercept_responses = False
|
macro.intercept_responses = False
|
||||||
return macro
|
return macro
|
||||||
|
|
||||||
|
def mock_generate_cert(cert_dir):
|
||||||
|
private_key = ('-----BEGIN PRIVATE KEY-----\n'
|
||||||
|
'MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDAoClrYUEB7lM0\n'
|
||||||
|
'zQaKkXZVG2d1Bu9hV8urpx0gNXMbyZ2m3xb+sKZju/FHPuWenA4KaN5gRUT+oLfv\n'
|
||||||
|
'tnF6Ia0jpRNWnX0Fyn/irdg1BWGJn7k7mJ2D0NXZQczn2+xxY05599NfGWqNKCYy\n'
|
||||||
|
'jhSwPsUK+sGJqi7aSDdlS97ZTjrQVTTFsC0+kSu4lS5fsWXxqrKLa6Ao8W7abVRO\n'
|
||||||
|
'JHazh/cxM4UKpgWU+E6yD4o4ZgHY+SMTVUh/IOM8DuOVyLEWtx4oLNiLMlpWT3qy\n'
|
||||||
|
'4IMpOF6VuU6JF2HGV13SoJfhsLXsPRbLVTAnZvJcZwtgDm6NfKapU8W8olkDV1Bf\n'
|
||||||
|
'YQEMSNX7AgMBAAECggEBAII0wUrAdrzjaIMsg9tu8FofKBPHGFDok9f4Iov/FUwX\n'
|
||||||
|
'QOXnrxeCOTb5d+L89SH9ws/ui0LwD+8+nJcA8DvqP6r0jtnhov0jIMcNVDSi6oeo\n'
|
||||||
|
'3AEY7ICJzcQJ4oRn+K+8vPNdPhfuikPYe9l4iSuJgpAlaGWyD/GlFyz12DFz2/Wu\n'
|
||||||
|
'NIcqR1ucvezRHn3eGMtvDv2WGaN4ifUc30k8XgSUesmwSI6beb5+hxq7wXfsurnP\n'
|
||||||
|
'EUrPY9ts3lfiAgxzTKOuj1VR5hn7cJyLN8jF0mZs4D6eSSHorIddhmaNiCq5ZbMd\n'
|
||||||
|
'QdlDiPvnXHT41OoXOb7tDEt7SGoiRh2noCZ1aZiSziECgYEA+tuPPLYWU6JRB6EW\n'
|
||||||
|
'PhbcXQbh3vML7eT1q7DOz0jYCojgT2+k7EWSI8T830oQyjbpe3Z86XEgH7UBjUgq\n'
|
||||||
|
'27nJ4E6dQDYGbYCKEklOoCGLE7A60i1feIz8otOQRrbQ4jcpibEgscA6gzHmunYf\n'
|
||||||
|
'De5euUgYW+Rq2Vmr6/NzUaUgui8CgYEAxJMDwPOGgiLM1cczlaSIU9Obz+cVnwWn\n'
|
||||||
|
'nsdKYMto2V3yKLydDfjsgOgzxHOxxy+5L645TPxK6CkiISuhJ93kAFFtx+1sCBCT\n'
|
||||||
|
'tVzY5robVAekxA9tlPIxtsn3+/axx3n6HnV0oA/XtxkuOS5JImgEdXqFwJZkerGE\n'
|
||||||
|
'waftIU2FCfUCgYEArl8+ErJzlJEIiCgWIPSdGuD00pfZW/TCPCT7rKRy3+fDHBR7\n'
|
||||||
|
'7Gxzp/9+0utV/mnrJBH5w/8JmGCmgoF+oRtk01FyBzdGgolN8GYajD6kwPvH917o\n'
|
||||||
|
'tRAzcC9lY3IigoxbiEWid0wqoBVoz4XaEkH2gA44OG/vQcQOOEYSi9cfh6sCgYBg\n'
|
||||||
|
'KLaOXdJvuIxRCzgNvMW/k+VFh3pJJx//COg2f2qT4mQCT3nYiutOh8hDEoFluc+y\n'
|
||||||
|
'Jlz7bvNJrE14wnn8IYxWJ383bMoLC+jlsDyeaW3S5kZQbmehk/SDwTrg86W1udKD\n'
|
||||||
|
'sdtSLU3N0LCO4jh+bzm3Ki9hrXALoOkbPoU+ZEhvPQKBgQDf79XQ3RNxZSk+eFyq\n'
|
||||||
|
'qD8ytVqxEoD+smPDflXXseVH6o+pNWrF8+A0KqmO8c+8KVzWj/OfULO6UbKd3E+x\n'
|
||||||
|
'4JGkWu9yF1lEgtHgibF2ER8zCSIL4ikOEasPCkrKj5SrS4Q+j4u5ha76dIc2CVu1\n'
|
||||||
|
'hkX2PQ1xU4ocu06k373sf73A4Q==\n'
|
||||||
|
'-----END PRIVATE KEY-----')
|
||||||
|
ca_key = ('-----BEGIN CERTIFICATE-----\n'
|
||||||
|
'MIIDjzCCAncCFQCjC8r+I4xa7JoGUJYGOTcqDROA0DANBgkqhkiG9w0BAQsFADBg\n'
|
||||||
|
'MQswCQYDVQQGEwJVUzERMA8GA1UECBMITWljaGlnYW4xEjAQBgNVBAcTCUFubiBB\n'
|
||||||
|
'cmJvcjEUMBIGA1UEChMLUGFwcHkgUHJveHkxFDASBgNVBAMTC1BhcHB5IFByb3h5\n'
|
||||||
|
'MB4XDTE1MTEyMDIxMTEzOVoXDTI1MTExNzIxMTEzOVowYDELMAkGA1UEBhMCVVMx\n'
|
||||||
|
'ETAPBgNVBAgTCE1pY2hpZ2FuMRIwEAYDVQQHEwlBbm4gQXJib3IxFDASBgNVBAoT\n'
|
||||||
|
'C1BhcHB5IFByb3h5MRQwEgYDVQQDEwtQYXBweSBQcm94eTCCASIwDQYJKoZIhvcN\n'
|
||||||
|
'AQEBBQADggEPADCCAQoCggEBAMCgKWthQQHuUzTNBoqRdlUbZ3UG72FXy6unHSA1\n'
|
||||||
|
'cxvJnabfFv6wpmO78Uc+5Z6cDgpo3mBFRP6gt++2cXohrSOlE1adfQXKf+Kt2DUF\n'
|
||||||
|
'YYmfuTuYnYPQ1dlBzOfb7HFjTnn3018Zao0oJjKOFLA+xQr6wYmqLtpIN2VL3tlO\n'
|
||||||
|
'OtBVNMWwLT6RK7iVLl+xZfGqsotroCjxbtptVE4kdrOH9zEzhQqmBZT4TrIPijhm\n'
|
||||||
|
'Adj5IxNVSH8g4zwO45XIsRa3Higs2IsyWlZPerLggyk4XpW5TokXYcZXXdKgl+Gw\n'
|
||||||
|
'tew9FstVMCdm8lxnC2AObo18pqlTxbyiWQNXUF9hAQxI1fsCAwEAAaNFMEMwEgYD\n'
|
||||||
|
'VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNo5o+5e\n'
|
||||||
|
'a0sNMlW/75VgGJCv2AcJMA0GCSqGSIb3DQEBCwUAA4IBAQBdJDhxbmoEe27bD8me\n'
|
||||||
|
'YTcLGjs/StKkSil7rLbX+tBCwtkm5UEEejBuAhKk2FuAXW8yR1FqKJSZwVCAocBT\n'
|
||||||
|
'Bo/+97Ee+h7ywrRFhATEr9D/TbbHKOjCjDzOMl9yLZa2DKErZjbI30ZD6NafWS/X\n'
|
||||||
|
'hx5X1cGohHcVVzT4jIgUEU70vvYfNn8CTZm4oJ7qqRe/uQPUYy0rwvbd60oprtGg\n'
|
||||||
|
'jNv1H5R4ODHUMBXAI9H7ft9cWrd0fBQjxhoj8pvgJXEZ52flXSqQc7qHLg1wO/zC\n'
|
||||||
|
'RUgpTcNAb2qCssBKbj+c1vKEPRUJfw6UYb0s1462rQNc8BgZiKaNbwokFmkAnjUg\n'
|
||||||
|
'AvnX\n'
|
||||||
|
'-----END CERTIFICATE-----')
|
||||||
|
return (ca_key, private_key)
|
||||||
|
|
||||||
|
def mock_config(mocker, http_config=None, socks_config=None):
|
||||||
|
# Mock config
|
||||||
|
mock_config = config.PappyConfig()
|
||||||
|
mock_config.socks_proxy = socks_config
|
||||||
|
mock_config.http_proxy = http_config
|
||||||
|
mock_session = pappy.PappySession(mock_config)
|
||||||
|
mocker.patch.object(pappy, 'session', new=mock_session)
|
||||||
|
mocker.patch("pappyproxy.proxy.load_certs_from_dir", new=mock_generate_cert)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue