def view_websocket_messages(self): flow = self.flow assert isinstance(flow, http.HTTPFlow) assert flow.websocket is not None if not flow.websocket.messages: return searchable.Searchable( [urwid.Text(("highlight", "No messages."))]) viewmode = self.master.commands.call("console.flowview.mode") widget_lines = [] for m in flow.websocket.messages: _, lines, _ = contentviews.get_message_content_view( viewmode, m, flow) for line in lines: if m.from_client: line.insert( 0, ("from_client", f"{common.SYMBOL_FROM_CLIENT} ")) else: line.insert(0, ("to_client", f"{common.SYMBOL_TO_CLIENT} ")) widget_lines.append(urwid.Text(line)) if flow.intercepted: markup = widget_lines[-1].get_text()[0] widget_lines[-1].set_text(("intercept", markup)) widget_lines.insert( 0, self._contentview_status_bar(viewmode.capitalize(), viewmode)) return searchable.Searchable(widget_lines)
def conn_text(self, conn): if conn: txt = common.format_keyvals( [(h + ":", v) for (h, v) in conn.headers.items(multi=True)], key="header", val="text") viewmode = self.viewmode_get() msg, body = self.content_view(viewmode, conn) cols = [ urwid.Text([ ("heading", msg), ]), urwid.Text([ " ", ('heading', "["), ('heading_key', "m"), ('heading', (":%s]" % viewmode)), ], align="right") ] title = urwid.AttrWrap(urwid.Columns(cols), "heading") txt.append(title) txt.extend(body) else: txt = [ urwid.Text(""), urwid.Text([ ("highlight", "No response. Press "), ("key", "e"), ("highlight", " and edit any aspect to add one."), ]) ] return searchable.Searchable(self.view, txt)
def view_tcp_stream(self) -> urwid.Widget: flow = self.flow assert isinstance(flow, tcp.TCPFlow) if not flow.messages: return searchable.Searchable( [urwid.Text(("highlight", "No messages."))]) viewmode = self.master.commands.call("console.flowview.mode") # Merge adjacent TCP "messages". For detailed explanation of this code block see: # https://github.com/mitmproxy/mitmproxy/pull/3970/files/469bd32582f764f9a29607efa4f5b04bd87961fb#r418670880 from_client = None messages = [] for message in flow.messages: if message.from_client is not from_client: messages.append(message.content) from_client = message.from_client else: messages[-1] += message.content widget_lines = [] from_client = flow.messages[0].from_client for m in messages: _, lines, _ = contentviews.get_tcp_content_view(viewmode, m, flow) for line in lines: if from_client: line.insert( 0, ("from_client", f"{common.SYMBOL_FROM_CLIENT} ")) else: line.insert(0, ("to_client", f"{common.SYMBOL_TO_CLIENT} ")) widget_lines.append(urwid.Text(line)) from_client = not from_client if flow.intercepted: markup = widget_lines[-1].get_text()[0] widget_lines[-1].set_text(("intercept", markup)) widget_lines.insert( 0, self._contentview_status_bar(viewmode.capitalize(), viewmode)) return searchable.Searchable(widget_lines)
def view_websocket_messages(self): flow = self.flow assert isinstance(flow, http.HTTPFlow) assert flow.websocket is not None if not flow.websocket.messages: return searchable.Searchable( [urwid.Text(("highlight", "No messages."))]) viewmode = self.master.commands.call("console.flowview.mode") widget_lines = [] for m in flow.websocket.messages: _, lines, _ = contentviews.get_message_content_view( viewmode, m, flow) for line in lines: if m.from_client: line.insert(0, self.FROM_CLIENT_MARKER) else: line.insert(0, self.TO_CLIENT_MARKER) widget_lines.append(urwid.Text(line)) if flow.websocket.closed_by_client is not None: widget_lines.append( urwid.Text([ (self.FROM_CLIENT_MARKER if flow.websocket.closed_by_client else self.TO_CLIENT_MARKER), ("alert" if flow.websocket.close_code in (1000, 1001, 1005) else "error", f"Connection closed: {flow.websocket.close_code} {flow.websocket.close_reason}" ) ])) if flow.intercepted: markup = widget_lines[-1].get_text()[0] widget_lines[-1].set_text(("intercept", markup)) widget_lines.insert( 0, self._contentview_status_bar(viewmode.capitalize(), viewmode)) return searchable.Searchable(widget_lines)
def conn_text(self, conn): if conn: hdrs = [] for k, v in conn.headers.fields: # This will always force an ascii representation of headers. For example, if the server sends a # # X-Authors: Made with ❤ in Hamburg # # header, mitmproxy will display the following: # # X-Authors: Made with \xe2\x9d\xa4 in Hamburg. # # The alternative would be to just use the header's UTF-8 representation and maybe # do `str.replace("\t", "\\t")` to exempt tabs from urwid's special characters escaping [1]. # That would in some terminals allow rendering UTF-8 characters, but the mapping # wouldn't be bijective, i.e. a user couldn't distinguish "\\t" and "\t". # Also, from a security perspective, a mitmproxy user couldn't be fooled by homoglyphs. # # 1) https://github.com/mitmproxy/mitmproxy/issues/1833 # https://github.com/urwid/urwid/blob/6608ee2c9932d264abd1171468d833b7a4082e13/urwid/display_common.py#L35-L36, k = strutils.bytes_to_escaped_str(k) + ":" v = strutils.bytes_to_escaped_str(v) hdrs.append((k, v)) txt = common.format_keyvals(hdrs, key_format="header") viewmode = self.master.commands.call("console.flowview.mode") msg, body = self.content_view(viewmode, conn) cols = [ urwid.Text([ ("heading", msg), ]), urwid.Text([ " ", ('heading', "["), ('heading_key', "m"), ('heading', (":%s]" % viewmode)), ], align="right") ] title = urwid.AttrWrap(urwid.Columns(cols), "heading") txt.append(title) txt.extend(body) else: txt = [ urwid.Text(""), urwid.Text([ ("highlight", "No response. Press "), ("key", "e"), ("highlight", " and edit any aspect to add one."), ]) ] return searchable.Searchable(txt)
def conn_text(self, conn, flowtype): _conn = conn if flowtype is FlowType.Request: conn = conn.request else: conn = conn.response if conn: txt = common.format_keyvals( [(h + ":", v) for (h, v) in conn.headers.items(multi=True)], key="header", val="text") viewmode = self.master.commands.call("console.flowview.mode") msg, body = self.content_view(viewmode, _conn, flowtype) cols = [ urwid.Text([ ("heading", msg), ]), urwid.Text([ " ", ('heading', "["), ('heading_key', "m"), ('heading', (":%s]" % viewmode)), ], align="right") ] title = urwid.AttrWrap(urwid.Columns(cols), "heading") txt.append(title) txt.extend(body) else: txt = [ urwid.Text(""), urwid.Text([ ("highlight", "No response. Press "), ("key", "e"), ("highlight", " and edit any aspect to add one."), ]) ] return searchable.Searchable(txt)
def flowdetails(state, flow): text = [] cc = flow.client_conn sc = flow.server_conn req = flow.request resp = flow.response if sc is not None: text.append(urwid.Text([("head", "Server Connection:")])) parts = [ ["Address", repr(sc.address)], ["Resolved Address", repr(sc.ip_address)], ] text.extend( common.format_keyvals(parts, key="key", val="text", indent=4)) c = sc.cert if c: text.append(urwid.Text([("head", "Server Certificate:")])) parts = [["Type", "%s, %s bits" % c.keyinfo], ["SHA1 digest", c.digest("sha1")], ["Valid to", str(c.notafter)], ["Valid from", str(c.notbefore)], ["Serial", str(c.serial)], [ "Subject", urwid.BoxAdapter( urwid.ListBox( common.format_keyvals(c.subject, key="highlight", val="text")), len(c.subject)) ], [ "Issuer", urwid.BoxAdapter( urwid.ListBox( common.format_keyvals(c.issuer, key="highlight", val="text")), len(c.issuer)) ]] if c.altnames: parts.append( ["Alt names", ", ".join(str(x) for x in c.altnames)]) text.extend( common.format_keyvals(parts, key="key", val="text", indent=4)) if cc is not None: text.append(urwid.Text([("head", "Client Connection:")])) parts = [ ["Address", repr(cc.address)], ] if cc.sni: parts.append(["Server Name Indication", cc.sni]) text.extend( common.format_keyvals(parts, key="key", val="text", indent=4)) parts = [] if cc is not None and cc.timestamp_start: parts.append([ "Client conn. established", maybe_timestamp(cc, "timestamp_start") ]) if cc.ssl_established: parts.append([ "Client conn. TLS handshake", maybe_timestamp(cc, "timestamp_ssl_setup") ]) if sc is not None and sc.timestamp_start: parts.append( ["Server conn. initiated", maybe_timestamp(sc, "timestamp_start")]) parts.append([ "Server conn. TCP handshake", maybe_timestamp(sc, "timestamp_tcp_setup") ]) if sc.ssl_established: parts.append([ "Server conn. TLS handshake", maybe_timestamp(sc, "timestamp_ssl_setup") ]) if req is not None and req.timestamp_start: parts.append( ["First request byte", maybe_timestamp(req, "timestamp_start")]) parts.append( ["Request complete", maybe_timestamp(req, "timestamp_end")]) if resp is not None and resp.timestamp_start: parts.append( ["First response byte", maybe_timestamp(resp, "timestamp_start")]) parts.append( ["Response complete", maybe_timestamp(resp, "timestamp_end")]) if parts: # sort operations by timestamp parts = sorted(parts, key=lambda p: p[1]) text.append(urwid.Text([("head", "Timing:")])) text.extend( common.format_keyvals(parts, key="key", val="text", indent=4)) return searchable.Searchable(state, text)
def flowdetails(state, flow: mitmproxy.flow.Flow): text = [] sc = flow.server_conn cc = flow.client_conn req: typing.Optional[http.Request] resp: typing.Optional[http.Response] if isinstance(flow, http.HTTPFlow): req = flow.request resp = flow.response else: req = None resp = None metadata = flow.metadata if metadata is not None and len(metadata) > 0: parts = [(str(k), repr(v)) for k, v in metadata.items()] text.append(urwid.Text([("head", "Metadata:")])) text.extend(common.format_keyvals(parts, indent=4)) if sc is not None and sc.peername: text.append(urwid.Text([("head", "Server Connection:")])) parts = [ ("Address", human.format_address(sc.address)), ] if sc.peername: parts.append(("Resolved Address", human.format_address(sc.peername))) if resp: parts.append(("HTTP Version", resp.http_version)) if sc.alpn: parts.append(("ALPN", strutils.bytes_to_escaped_str(sc.alpn))) text.extend( common.format_keyvals(parts, indent=4) ) if sc.certificate_list: c = sc.certificate_list[0] text.append(urwid.Text([("head", "Server Certificate:")])) parts = [ ("Type", "%s, %s bits" % c.keyinfo), ("SHA256 digest", c.fingerprint().hex()), ("Valid to", str(c.notafter)), ("Valid from", str(c.notbefore)), ("Serial", str(c.serial)), ("Subject", urwid.Pile(common.format_keyvals(c.subject, key_format="highlight"))), ("Issuer", urwid.Pile(common.format_keyvals(c.issuer, key_format="highlight"))) ] if c.altnames: parts.append(("Alt names", ", ".join(c.altnames))) text.extend( common.format_keyvals(parts, indent=4) ) if cc is not None: text.append(urwid.Text([("head", "Client Connection:")])) parts = [ ("Address", human.format_address(cc.peername)), ] if req: parts.append(("HTTP Version", req.http_version)) if cc.tls_version: parts.append(("TLS Version", cc.tls_version)) if cc.sni: parts.append(("Server Name Indication", cc.sni)) if cc.cipher: parts.append(("Cipher Name", cc.cipher)) if cc.alpn: parts.append(("ALPN", strutils.bytes_to_escaped_str(cc.alpn))) text.extend( common.format_keyvals(parts, indent=4) ) parts = [] if cc is not None and cc.timestamp_start: parts.append( ( "Client conn. established", maybe_timestamp(cc, "timestamp_start") ) ) if cc.tls_established: parts.append( ( "Client conn. TLS handshake", maybe_timestamp(cc, "timestamp_tls_setup") ) ) parts.append( ( "Client conn. closed", maybe_timestamp(cc, "timestamp_end") ) ) if sc is not None and sc.timestamp_start: parts.append( ( "Server conn. initiated", maybe_timestamp(sc, "timestamp_start") ) ) parts.append( ( "Server conn. TCP handshake", maybe_timestamp(sc, "timestamp_tcp_setup") ) ) if sc.tls_established: parts.append( ( "Server conn. TLS handshake", maybe_timestamp(sc, "timestamp_tls_setup") ) ) parts.append( ( "Server conn. closed", maybe_timestamp(sc, "timestamp_end") ) ) if req is not None and req.timestamp_start: parts.append( ( "First request byte", maybe_timestamp(req, "timestamp_start") ) ) parts.append( ( "Request complete", maybe_timestamp(req, "timestamp_end") ) ) if resp is not None and resp.timestamp_start: parts.append( ( "First response byte", maybe_timestamp(resp, "timestamp_start") ) ) parts.append( ( "Response complete", maybe_timestamp(resp, "timestamp_end") ) ) if parts: # sort operations by timestamp parts = sorted(parts, key=lambda p: p[1]) text.append(urwid.Text([("head", "Timing:")])) text.extend(common.format_keyvals(parts, indent=4)) return searchable.Searchable(text)
def flowdetails(state, flow: http.HTTPFlow): text = [] sc = flow.server_conn cc = flow.client_conn req = flow.request resp = flow.response metadata = flow.metadata if metadata is not None and len(metadata) > 0: parts = [[str(k), repr(v)] for k, v in metadata.items()] text.append(urwid.Text([("head", "Metadata:")])) text.extend( common.format_keyvals(parts, key="key", val="text", indent=4)) if sc is not None and sc.ip_address: text.append(urwid.Text([("head", "Server Connection:")])) parts = [ ["Address", human.format_address(sc.address)], ] if sc.ip_address: parts.append( ["Resolved Address", human.format_address(sc.ip_address)]) if resp: parts.append(["HTTP Version", resp.http_version]) if sc.alpn_proto_negotiated: parts.append(["ALPN", sc.alpn_proto_negotiated]) text.extend( common.format_keyvals(parts, key="key", val="text", indent=4)) c = sc.cert if c: text.append(urwid.Text([("head", "Server Certificate:")])) parts = [["Type", "%s, %s bits" % c.keyinfo], ["SHA1 digest", c.digest("sha1")], ["Valid to", str(c.notafter)], ["Valid from", str(c.notbefore)], ["Serial", str(c.serial)], [ "Subject", urwid.BoxAdapter( urwid.ListBox( common.format_keyvals(c.subject, key="highlight", val="text")), len(c.subject)) ], [ "Issuer", urwid.BoxAdapter( urwid.ListBox( common.format_keyvals(c.issuer, key="highlight", val="text")), len(c.issuer)) ]] if c.altnames: parts.append([ "Alt names", ", ".join( strutils.bytes_to_escaped_str(x) for x in c.altnames) ]) text.extend( common.format_keyvals(parts, key="key", val="text", indent=4)) if cc is not None: text.append(urwid.Text([("head", "Client Connection:")])) parts = [ ["Address", "{}:{}".format(cc.address[0], cc.address[1])], ] if req: parts.append(["HTTP Version", req.http_version]) if cc.tls_version: parts.append(["TLS Version", cc.tls_version]) if cc.sni: parts.append(["Server Name Indication", cc.sni]) if cc.cipher_name: parts.append(["Cipher Name", cc.cipher_name]) if cc.alpn_proto_negotiated: parts.append(["ALPN", cc.alpn_proto_negotiated]) text.extend( common.format_keyvals(parts, key="key", val="text", indent=4)) parts = [] if cc is not None and cc.timestamp_start: parts.append([ "Client conn. established", maybe_timestamp(cc, "timestamp_start") ]) if cc.ssl_established: parts.append([ "Client conn. TLS handshake", maybe_timestamp(cc, "timestamp_ssl_setup") ]) if sc is not None and sc.timestamp_start: parts.append( ["Server conn. initiated", maybe_timestamp(sc, "timestamp_start")]) parts.append([ "Server conn. TCP handshake", maybe_timestamp(sc, "timestamp_tcp_setup") ]) if sc.ssl_established: parts.append([ "Server conn. TLS handshake", maybe_timestamp(sc, "timestamp_ssl_setup") ]) if req is not None and req.timestamp_start: parts.append( ["First request byte", maybe_timestamp(req, "timestamp_start")]) parts.append( ["Request complete", maybe_timestamp(req, "timestamp_end")]) if resp is not None and resp.timestamp_start: parts.append( ["First response byte", maybe_timestamp(resp, "timestamp_start")]) parts.append( ["Response complete", maybe_timestamp(resp, "timestamp_end")]) if parts: # sort operations by timestamp parts = sorted(parts, key=lambda p: p[1]) text.append(urwid.Text([("head", "Timing:")])) text.extend( common.format_keyvals(parts, key="key", val="text", indent=4)) return searchable.Searchable(text)