mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 10:16:27 +00:00
Merge branch 'master' into py38
This commit is contained in:
commit
276b741482
@ -12,6 +12,7 @@ Unreleased: mitmproxy next
|
||||
* Updated imports and styles for web scanner helper addons. (@anneborcherding)
|
||||
* Inform when underscore-formatted options are used in client arg. (@jrblixt)
|
||||
* Binaries are now built with Python 3.9 (@mhils)
|
||||
* Fixed the web UI showing blank page on clicking details tab when server address is missing (@samhita-sopho)
|
||||
|
||||
* --- TODO: add new PRs above this line ---
|
||||
|
||||
|
@ -23,7 +23,7 @@ from mitmproxy import ctx
|
||||
from mitmproxy import io
|
||||
from mitmproxy import http
|
||||
from mitmproxy import tcp
|
||||
from mitmproxy.utils import human
|
||||
from mitmproxy.utils import compat, human
|
||||
|
||||
|
||||
# The underlying sorted list implementation expects the sort key to be stable
|
||||
@ -460,8 +460,12 @@ class View(collections.abc.Sequence):
|
||||
req = http.HTTPRequest.make(method.upper(), url)
|
||||
except ValueError as e:
|
||||
raise exceptions.CommandError("Invalid URL: %s" % e)
|
||||
c = connections.ClientConnection.make_dummy(("", 0))
|
||||
s = connections.ServerConnection.make_dummy((req.host, req.port))
|
||||
if compat.new_proxy_core: # pragma: no cover
|
||||
c = compat.Client(("", 0), ("", 0), req.timestamp_start - 0.0001)
|
||||
s = compat.Server((req.host, req.port))
|
||||
else: # pragma: no cover
|
||||
c = connections.ClientConnection.make_dummy(("", 0))
|
||||
s = connections.ServerConnection.make_dummy((req.host, req.port))
|
||||
f = http.HTTPFlow(c, s)
|
||||
f.request = req
|
||||
f.request.headers["Host"] = req.host
|
||||
|
@ -86,6 +86,15 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject):
|
||||
def __hash__(self):
|
||||
return hash(self.id)
|
||||
|
||||
# Sans-io attributes.
|
||||
state = 0
|
||||
sockname = ("", 0)
|
||||
error = None
|
||||
tls = None
|
||||
certificate_list = None
|
||||
alpn_offers = None
|
||||
cipher_list = None
|
||||
|
||||
_stateobject_attributes = dict(
|
||||
id=str,
|
||||
address=tuple,
|
||||
@ -100,6 +109,14 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject):
|
||||
alpn_proto_negotiated=bytes,
|
||||
tls_version=str,
|
||||
tls_extensions=typing.List[typing.Tuple[int, bytes]],
|
||||
# sans-io exclusives
|
||||
state=int,
|
||||
sockname=tuple,
|
||||
error=str,
|
||||
tls=bool,
|
||||
certificate_list=typing.List[certs.Cert],
|
||||
alpn_offers=typing.List[bytes],
|
||||
cipher_list=typing.List[str],
|
||||
)
|
||||
|
||||
def send(self, message):
|
||||
@ -130,6 +147,13 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject):
|
||||
alpn_proto_negotiated=None,
|
||||
tls_version=None,
|
||||
tls_extensions=None,
|
||||
state=0,
|
||||
sockname=("", 0),
|
||||
error=None,
|
||||
tls=False,
|
||||
certificate_list=[],
|
||||
alpn_offers=[],
|
||||
cipher_list=[],
|
||||
))
|
||||
|
||||
def convert_to_tls(self, cert, *args, **kwargs):
|
||||
@ -221,6 +245,16 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject):
|
||||
def __hash__(self):
|
||||
return hash(self.id)
|
||||
|
||||
# Sans-io attributes.
|
||||
state = 0
|
||||
error = None
|
||||
tls = None
|
||||
certificate_list = None
|
||||
alpn_offers = None
|
||||
cipher_name = None
|
||||
cipher_list = None
|
||||
via2 = None
|
||||
|
||||
_stateobject_attributes = dict(
|
||||
id=str,
|
||||
address=tuple,
|
||||
@ -235,6 +269,15 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject):
|
||||
timestamp_tcp_setup=float,
|
||||
timestamp_tls_setup=float,
|
||||
timestamp_end=float,
|
||||
# sans-io exclusives
|
||||
state=int,
|
||||
error=str,
|
||||
tls=bool,
|
||||
certificate_list=typing.List[certs.Cert],
|
||||
alpn_offers=typing.List[bytes],
|
||||
cipher_name=str,
|
||||
cipher_list=typing.List[str],
|
||||
via2=None,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@ -259,7 +302,15 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject):
|
||||
timestamp_tcp_setup=None,
|
||||
timestamp_tls_setup=None,
|
||||
timestamp_end=None,
|
||||
via=None
|
||||
via=None,
|
||||
state=0,
|
||||
error=None,
|
||||
tls=False,
|
||||
certificate_list=[],
|
||||
alpn_offers=[],
|
||||
cipher_name=None,
|
||||
cipher_list=[],
|
||||
via2=None,
|
||||
))
|
||||
|
||||
def connect(self):
|
||||
|
@ -197,6 +197,39 @@ def convert_8_9(data):
|
||||
return data
|
||||
|
||||
|
||||
def convert_9_10(data):
|
||||
data["version"] = 10
|
||||
|
||||
def conv_conn(conn):
|
||||
conn["state"] = 0
|
||||
conn["error"] = None
|
||||
conn["tls"] = conn["tls_established"]
|
||||
alpn = conn["alpn_proto_negotiated"]
|
||||
conn["alpn_offers"] = [alpn] if alpn else None
|
||||
cipher = conn["cipher_name"]
|
||||
conn["cipher_list"] = [cipher] if cipher else None
|
||||
|
||||
def conv_cconn(conn):
|
||||
conn["sockname"] = ("", 0)
|
||||
cc = conn["clientcert"]
|
||||
conn["certificate_list"] = [cc] if cc else None
|
||||
conv_conn(conn)
|
||||
|
||||
def conv_sconn(conn):
|
||||
crt = conn["cert"]
|
||||
conn["certificate_list"] = [crt] if crt else None
|
||||
conn["cipher_name"] = None
|
||||
conn["via2"] = None
|
||||
conv_conn(conn)
|
||||
|
||||
conv_cconn(data["client_conn"])
|
||||
conv_sconn(data["server_conn"])
|
||||
if data["server_conn"]["via"]:
|
||||
conv_sconn(data["server_conn"]["via"])
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def _convert_dict_keys(o: Any) -> Any:
|
||||
if isinstance(o, dict):
|
||||
return {strutils.always_str(k): _convert_dict_keys(v) for k, v in o.items()}
|
||||
@ -253,6 +286,7 @@ converters = {
|
||||
6: convert_6_7,
|
||||
7: convert_7_8,
|
||||
8: convert_8_9,
|
||||
9: convert_9_10,
|
||||
}
|
||||
|
||||
|
||||
|
@ -165,6 +165,13 @@ def tclient_conn():
|
||||
alpn_proto_negotiated=b"http/1.1",
|
||||
tls_version="TLSv1.2",
|
||||
tls_extensions=[(0x00, bytes.fromhex("000e00000b6578616d"))],
|
||||
state=0,
|
||||
sockname=("", 0),
|
||||
error=None,
|
||||
tls=False,
|
||||
certificate_list=[],
|
||||
alpn_offers=[],
|
||||
cipher_list=[],
|
||||
))
|
||||
c.reply = controller.DummyReply()
|
||||
c.rfile = io.BytesIO()
|
||||
@ -191,6 +198,14 @@ def tserver_conn():
|
||||
alpn_proto_negotiated=None,
|
||||
tls_version="TLSv1.2",
|
||||
via=None,
|
||||
state=0,
|
||||
error=None,
|
||||
tls=False,
|
||||
certificate_list=[],
|
||||
alpn_offers=[],
|
||||
cipher_name=None,
|
||||
cipher_list=[],
|
||||
via2=None,
|
||||
))
|
||||
c.reply = controller.DummyReply()
|
||||
c.rfile = io.BytesIO()
|
||||
|
@ -12,7 +12,12 @@ def maybe_timestamp(base, attr):
|
||||
if base is not None and getattr(base, attr):
|
||||
return human.format_timestamp_with_milli(getattr(base, attr))
|
||||
else:
|
||||
return "active"
|
||||
# in mitmdump we serialize before a connection is closed.
|
||||
# loading those flows at a later point shouldn't display "active".
|
||||
# We also use a ndash (and not a regular dash) so that it is sorted
|
||||
# after other timestamps. We may need to revisit that in the future if it turns out
|
||||
# to render ugly in consoles.
|
||||
return "–"
|
||||
|
||||
|
||||
def flowdetails(state, flow: mitmproxy.flow.Flow):
|
||||
|
@ -8,7 +8,7 @@ MITMPROXY = "mitmproxy " + VERSION
|
||||
|
||||
# Serialization format version. This is displayed nowhere, it just needs to be incremented by one
|
||||
# for each change in the file format.
|
||||
FLOW_FORMAT_VERSION = 9
|
||||
FLOW_FORMAT_VERSION = 10
|
||||
|
||||
|
||||
def get_dev_version() -> str:
|
||||
|
@ -47,4 +47,24 @@ describe('Details Component', () => {
|
||||
tree = details.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render correctly when server address is missing', () => {
|
||||
let tflowServerAddressNull = tflow
|
||||
|
||||
tflowServerAddressNull.server_conn.address = null
|
||||
tflowServerAddressNull.server_conn.ip_address = null
|
||||
tflowServerAddressNull.server_conn.alpn_proto_negotiated = null
|
||||
tflowServerAddressNull.server_conn.sni = null
|
||||
tflowServerAddressNull.server_conn.ssl_established = false
|
||||
tflowServerAddressNull.server_conn.tls_version = null
|
||||
tflowServerAddressNull.server_conn.timestamp_tcp_setup = null
|
||||
tflowServerAddressNull.server_conn.timestamp_ssl_setup = null
|
||||
tflowServerAddressNull.server_conn.timestamp_start = null
|
||||
tflowServerAddressNull.server_conn.timestamp_end = null
|
||||
|
||||
let details = renderer.create(<Details flow={tflowServerAddressNull}/>),
|
||||
tree = details.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -237,6 +237,123 @@ exports[`Details Component should render correctly 1`] = `
|
||||
</section>
|
||||
`;
|
||||
|
||||
exports[`Details Component should render correctly when server address is missing 1`] = `
|
||||
<section
|
||||
className="detail"
|
||||
>
|
||||
<h4>
|
||||
Client Connection
|
||||
</h4>
|
||||
<table
|
||||
className="connection-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Address:
|
||||
</td>
|
||||
<td>
|
||||
127.0.0.1:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="TLS Server Name Indication"
|
||||
>
|
||||
TLS SNI:
|
||||
</abbr>
|
||||
</td>
|
||||
<td>
|
||||
address
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TLS version:
|
||||
</td>
|
||||
<td>
|
||||
TLSv1.2
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
cipher name:
|
||||
</td>
|
||||
<td>
|
||||
cipher
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="ALPN protocol negotiated"
|
||||
>
|
||||
ALPN:
|
||||
</abbr>
|
||||
</td>
|
||||
<td>
|
||||
http/1.1
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div />
|
||||
<div>
|
||||
<h4>
|
||||
Timing
|
||||
</h4>
|
||||
<table
|
||||
className="timing-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr />
|
||||
<tr />
|
||||
<tr />
|
||||
<tr />
|
||||
<tr />
|
||||
<tr>
|
||||
<td>
|
||||
Client conn. established
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1970-01-01 00:00:01.000
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Client conn. SSL handshake
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1970-01-01 00:00:02.000
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
First response byte
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
2017-05-21 12:38:32.481
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Response complete
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
2017-05-21 12:38:32.481
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
|
||||
exports[`TimeStamp Component should render correctly 1`] = `
|
||||
<tr>
|
||||
<td>
|
||||
|
@ -20,14 +20,14 @@ export function TimeStamp({ t, deltaTo, title }) {
|
||||
)
|
||||
}
|
||||
|
||||
export function ConnectionInfo({ conn }) {
|
||||
export function ConnectionInfo({ conn }) {
|
||||
return (
|
||||
<table className="connection-table">
|
||||
<tbody>
|
||||
<tr key="address">
|
||||
<tr key="address">
|
||||
<td>Address:</td>
|
||||
<td>{conn.address.join(':')}</td>
|
||||
</tr>
|
||||
</tr>
|
||||
{conn.sni && (
|
||||
<tr key="sni">
|
||||
<td><abbr title="TLS Server Name Indication">TLS SNI:</abbr></td>
|
||||
@ -136,9 +136,13 @@ export default function Details({ flow }) {
|
||||
<h4>Client Connection</h4>
|
||||
<ConnectionInfo conn={flow.client_conn}/>
|
||||
|
||||
<h4>Server Connection</h4>
|
||||
<ConnectionInfo conn={flow.server_conn}/>
|
||||
|
||||
{flow.server_conn.address &&
|
||||
[
|
||||
<h4>Server Connection</h4>,
|
||||
<ConnectionInfo conn={flow.server_conn}/>
|
||||
]
|
||||
}
|
||||
|
||||
<CertificateInfo flow={flow}/>
|
||||
|
||||
<Timing flow={flow}/>
|
||||
|
Loading…
Reference in New Issue
Block a user