From 1efe44745be86490fa83cba6d5037bf05c230510 Mon Sep 17 00:00:00 2001 From: gorogoroumaru Date: Sun, 30 Aug 2020 13:10:11 +0000 Subject: [PATCH] make columns configurable and customizable --- mitmproxy/tools/cmdline.py | 1 + mitmproxy/tools/web/static/app.css | Bin 15710 -> 15748 bytes mitmproxy/tools/web/static/app.js | Bin 185795 -> 187095 bytes mitmproxy/tools/web/webaddons.py | 6 +++++ web/src/css/flowtable.less | 3 +++ .../components/FlowTable/FlowRowSpec.js | 9 +++++-- .../components/FlowTable/FlowTableHeadSpec.js | 6 ++++- .../__snapshots__/FlowTableHeadSpec.js.snap | 6 +++++ .../js/components/FlowTable/FlowColumns.jsx | 20 ++++++++++++++- web/src/js/components/FlowTable/FlowRow.jsx | 16 +++++++++--- .../js/components/FlowTable/FlowTableHead.jsx | 23 +++++++++++++++--- 11 files changed, 79 insertions(+), 11 deletions(-) diff --git a/mitmproxy/tools/cmdline.py b/mitmproxy/tools/cmdline.py index a94f28206..b345a4ccf 100644 --- a/mitmproxy/tools/cmdline.py +++ b/mitmproxy/tools/cmdline.py @@ -137,6 +137,7 @@ def mitmweb(opts): opts.make_parser(group, "web_open_browser") opts.make_parser(group, "web_port", metavar="PORT") opts.make_parser(group, "web_host", metavar="HOST") + opts.make_parser(group, "web_columns") common_options(parser, opts) group = parser.add_argument_group( diff --git a/mitmproxy/tools/web/static/app.css b/mitmproxy/tools/web/static/app.css index bd69915bc6a38d811c51b45e977ada9a75215f22..70b37ea6ab8db6247bd63261c3c8496b2fabb651 100644 GIT binary patch delta 33 ocmcat)l$77R&uh9B&R@eNn&n6b$Mn=NrqKoX-WR(07*U-0Obh`fB*mh delta 12 TcmZpvzE`y&R&sN*B%=xdCm00s diff --git a/mitmproxy/tools/web/static/app.js b/mitmproxy/tools/web/static/app.js index f97d73054bf4b2f779e7e37f5ca5898aee04c39f..936f0519c546c2120cd08367979ef15548385b80 100644 GIT binary patch delta 1294 zcmcIjO=uHA6lS7DL_}<*trav`Yutr(OqB{IuGO|^(W;c>pe?aXb|+?Wva{~Yw$>6$ z5fLvvIEOt5ZNWcm3b6$7pq}*L(VHH;c=D(o1id-iv^APuJt^8IP$ns(s_V7BkiC^XkT^*xz0%2CM~Hz2$dlA z0}M3xQQ{Y!^QefKF-C1Gnh^21kE)KZyVT&@|{1C+F`MbPMN^Pk24x zD#$vi5rq?`=!$JpM;k}sWE=2yCa zFF}9c4ud_QD?qO!$AWJ+!Rd<);#I6ojv+7V86(-0omXoXGYkW39_GI1MC<7sTIG`p zYp4-R$SK6SbS~Z>-!VmGzt?>|lAb8$D1kP|9^%x?s#+?hQbQ#Mf)2jURZW8yb+DES zF>8!`gVY+5!q9e1;#-)hK6Io@AS1Sk zW+9X)StjJBoqZcQ+`=?o@aTAymr5%VJ<(EzheLBQxl{d^nak#4n5Si|^Yx8J3@Wna zwpOXSv8{a7QX9owxv8n%MY*j+)34$QX^l|Kvf;$=Vk@BH+G1vJ16Ct?_0?i;q*-rp wn}|*C3YIPcL!>H4ryBF@f4EVfTlLLl7lN6xOlkurVlTe|VvrVEE1e3LDsP>%sNv!SV80h5!mGn1pC6_@Wh0SA+4tH_hXtQ3<^;Te?>uNRk*0RbnMz&!y3lMlQGlQFIomr#!ZHh_nJvCh*;3tpET3 diff --git a/mitmproxy/tools/web/webaddons.py b/mitmproxy/tools/web/webaddons.py index 5e7d7982d..b792c5420 100644 --- a/mitmproxy/tools/web/webaddons.py +++ b/mitmproxy/tools/web/webaddons.py @@ -1,6 +1,8 @@ import webbrowser from mitmproxy import ctx +from typing import Sequence + class WebAddon: @@ -21,6 +23,10 @@ class WebAddon: "web_host", str, "127.0.0.1", "Web UI host." ) + loader.add_option( + "web_columns", Sequence[str], ["tls", "icon", "path", "method", "status", "size", "time"], + "Columns to show in the flow list" + ) def running(self): if hasattr(ctx.options, "web_open_browser") and ctx.options.web_open_browser: diff --git a/web/src/css/flowtable.less b/web/src/css/flowtable.less index e8d3d5afc..f7771dd3f 100644 --- a/web/src/css/flowtable.less +++ b/web/src/css/flowtable.less @@ -125,6 +125,9 @@ .col-time { width: 50px; } + .col-timestamp { + width: auto; + } td.col-time, td.col-size { text-align: right; } diff --git a/web/src/js/__tests__/components/FlowTable/FlowRowSpec.js b/web/src/js/__tests__/components/FlowTable/FlowRowSpec.js index 7dfc1dcd0..d8ef1d3e0 100644 --- a/web/src/js/__tests__/components/FlowTable/FlowRowSpec.js +++ b/web/src/js/__tests__/components/FlowTable/FlowRowSpec.js @@ -1,12 +1,17 @@ import React from 'react' import renderer from 'react-test-renderer' import FlowRow from '../../../components/FlowTable/FlowRow' -import { TFlow } from '../../ducks/tutils' +import { TFlow, TStore } from '../../ducks/tutils' +import { Provider } from 'react-redux' describe('FlowRow Component', () => { let tFlow = new TFlow(), selectFn = jest.fn(), - flowRow = renderer.create(), + store = TStore(), + flowRow = renderer.create( + + + ), tree = flowRow.toJSON() it('should render correctly', () => { diff --git a/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.js b/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.js index 3b7302f22..977425e3f 100644 --- a/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.js +++ b/web/src/js/__tests__/components/FlowTable/FlowTableHeadSpec.js @@ -7,7 +7,11 @@ import { TStore } from '../../ducks/tutils' describe('FlowTableHead Component', () => { let sortFn = jest.fn(), - flowTableHead = renderer.create(), + store = TStore(), + flowTableHead = renderer.create( + + + ), tree =flowTableHead.toJSON() it('should render correctly', () => { diff --git a/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowTableHeadSpec.js.snap b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowTableHeadSpec.js.snap index 3f066c6e9..46617efd4 100644 --- a/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowTableHeadSpec.js.snap +++ b/web/src/js/__tests__/components/FlowTable/__snapshots__/FlowTableHeadSpec.js.snap @@ -79,6 +79,12 @@ exports[`FlowTableHead Component should render correctly 1`] = ` > Status + + TimeStamp + + {flow.request.timestamp_start ? ( + formatTimeStamp(flow.request.timestamp_start) + ) : ( + '...' + )} + + ) +} + +TimeStampColumn.headerClass = 'col-timestamp' +TimeStampColumn.headerName = 'TimeStamp' + export default [ TLSColumn, IconColumn, PathColumn, MethodColumn, StatusColumn, + TimeStampColumn, SizeColumn, TimeColumn, ] diff --git a/web/src/js/components/FlowTable/FlowRow.jsx b/web/src/js/components/FlowTable/FlowRow.jsx index 71a30e398..8325b41e7 100644 --- a/web/src/js/components/FlowTable/FlowRow.jsx +++ b/web/src/js/components/FlowTable/FlowRow.jsx @@ -1,8 +1,10 @@ import React from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import columns from './FlowColumns' +import {defaultColumnNames} from './FlowColumns' import { pure } from '../../utils' +import {getDisplayColumns} from './FlowTableHead' +import { connect } from 'react-redux' FlowRow.propTypes = { onSelect: PropTypes.func.isRequired, @@ -11,7 +13,7 @@ FlowRow.propTypes = { selected: PropTypes.bool, } -function FlowRow({ flow, selected, highlighted, onSelect }) { +function FlowRow({ flow, selected, highlighted, onSelect, displayColumnNames }) { const className = classnames({ 'selected': selected, 'highlighted': highlighted, @@ -20,13 +22,19 @@ function FlowRow({ flow, selected, highlighted, onSelect }) { 'has-response': flow.response, }) + const displayColumns = getDisplayColumns(displayColumnNames) + return ( onSelect(flow.id)}> - {columns.map(Column => ( + {displayColumns.map(Column => ( ))} ) } -export default pure(FlowRow) +export default connect( + state => ({ + displayColumnNames: state.options["web_columns"] ? state.options["web_columns"].value : defaultColumnNames, + }) +)(pure(FlowRow)) diff --git a/web/src/js/components/FlowTable/FlowTableHead.jsx b/web/src/js/components/FlowTable/FlowTableHead.jsx index bbd8c9169..be1b3d771 100644 --- a/web/src/js/components/FlowTable/FlowTableHead.jsx +++ b/web/src/js/components/FlowTable/FlowTableHead.jsx @@ -2,7 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' import classnames from 'classnames' -import columns from './FlowColumns' +import columns, {defaultColumnNames} from './FlowColumns' import { setSort } from '../../ducks/flows' @@ -10,14 +10,30 @@ FlowTableHead.propTypes = { setSort: PropTypes.func.isRequired, sortDesc: PropTypes.bool.isRequired, sortColumn: PropTypes.string, + displayColumnNames: PropTypes.array, } -export function FlowTableHead({ sortColumn, sortDesc, setSort }) { +export function getDisplayColumns(displayColumnNames) { + let displayColumns = [] + if (typeof displayColumnNames == "undefined") { + return columns + } + for (const column of columns) { + if (displayColumnNames.includes(column.name.slice(0,-6).toLowerCase())) { + displayColumns.push(column) + } + } + return displayColumns +} + +export function FlowTableHead({ sortColumn, sortDesc, setSort, displayColumnNames}) { const sortType = sortDesc ? 'sort-desc' : 'sort-asc' + const displayColumns = getDisplayColumns(displayColumnNames) + return ( - {columns.map(Column => ( + {displayColumns.map(Column => ( setSort(Column.name, Column.name !== sortColumn ? false : !sortDesc)}> @@ -32,6 +48,7 @@ export default connect( state => ({ sortDesc: state.flows.sort.desc, sortColumn: state.flows.sort.column, + displayColumnNames: state.options["web_columns"] ? state.options["web_columns"].value : defaultColumnNames, }), { setSort