From 51b45b8599346b2f483a97e192ff88922e21910a Mon Sep 17 00:00:00 2001 From: Matteo Luppi <100372313+lups2000@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:48:36 +0200 Subject: [PATCH] Display current status for each mode (#7097) * display current status for each mode * review changes * update snapshots * update tests * [autofix.ci] apply automated fixes * fix bug * use type --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- web/src/css/mode.less | 21 ++-- .../{ => Modes}/CaptureSetupSpec.tsx | 6 +- .../__snapshots__/CaptureSetupSpec.tsx.snap | 18 +++ .../Modes/__snapshots__/RegularSpec.tsx.snap | 19 ++- .../__snapshots__/CaptureSetupSpec.tsx.snap | 42 ------- web/src/js/components/CaptureSetup.tsx | 119 ------------------ web/src/js/components/MainView.tsx | 2 +- web/src/js/components/Modes/CaptureSetup.tsx | 99 +++++++++++++++ web/src/js/components/Modes/Local.tsx | 26 ++-- web/src/js/components/Modes/Regular.tsx | 21 ++-- web/src/js/components/Modes/Reverse.tsx | 22 ++-- .../js/components/Modes/ReverseToggleRow.tsx | 14 ++- web/src/js/components/Modes/Wireguard.tsx | 20 +-- 13 files changed, 218 insertions(+), 211 deletions(-) rename web/src/js/__tests__/components/{ => Modes}/CaptureSetupSpec.tsx (57%) create mode 100644 web/src/js/__tests__/components/Modes/__snapshots__/CaptureSetupSpec.tsx.snap delete mode 100644 web/src/js/__tests__/components/__snapshots__/CaptureSetupSpec.tsx.snap delete mode 100644 web/src/js/components/CaptureSetup.tsx create mode 100644 web/src/js/components/Modes/CaptureSetup.tsx diff --git a/web/src/css/mode.less b/web/src/css/mode.less index eddd2a2f1..c9073d1c0 100644 --- a/web/src/css/mode.less +++ b/web/src/css/mode.less @@ -5,6 +5,9 @@ .modes { padding: 1em 2em; + overflow-y: auto; + height: 100%; + width: 100vw; h3 { margin-top: 30px; @@ -47,9 +50,10 @@ } } - .mode-error { + .mode-status { margin-left: 10px; margin-top: 5px; + font-weight: 600; } .mode-local-input { @@ -81,13 +85,16 @@ margin: 0 5px; } + .mode-reverse-servers { + display: flex; + flex-direction: column; + gap: 10px; + } + .mode-reverse-add-server { margin-left: 10px; - margin-top: 15px; display: flex; flex-direction: row; - align-items: center; - justify-content: center; cursor: pointer; font-weight: 500; @@ -96,10 +103,4 @@ margin-right: 5px; } } - - .mode-reverse-servers { - display: flex; - flex-direction: column; - gap: 10px; - } } diff --git a/web/src/js/__tests__/components/CaptureSetupSpec.tsx b/web/src/js/__tests__/components/Modes/CaptureSetupSpec.tsx similarity index 57% rename from web/src/js/__tests__/components/CaptureSetupSpec.tsx rename to web/src/js/__tests__/components/Modes/CaptureSetupSpec.tsx index 89536430c..204a3da29 100644 --- a/web/src/js/__tests__/components/CaptureSetupSpec.tsx +++ b/web/src/js/__tests__/components/Modes/CaptureSetupSpec.tsx @@ -1,7 +1,7 @@ import * as React from "react"; -import { render } from "../test-utils"; -import CaptureSetup from "../../components/CaptureSetup"; -import { TStore } from "../ducks/tutils"; +import { render } from "../../test-utils"; +import CaptureSetup from "../../../components/Modes/CaptureSetup"; +import { TStore } from "../../ducks/tutils"; test("CaptureSetup", async () => { const store = TStore(); diff --git a/web/src/js/__tests__/components/Modes/__snapshots__/CaptureSetupSpec.tsx.snap b/web/src/js/__tests__/components/Modes/__snapshots__/CaptureSetupSpec.tsx.snap new file mode 100644 index 000000000..1d00ff95e --- /dev/null +++ b/web/src/js/__tests__/components/Modes/__snapshots__/CaptureSetupSpec.tsx.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CaptureSetup 1`] = ` + +
+

+ mitmproxy is running. +

+

+ No flows have been recorded yet. +
+ To start capturing traffic, please configure your settings in the Capture tab. +

+
+
+`; diff --git a/web/src/js/__tests__/components/Modes/__snapshots__/RegularSpec.tsx.snap b/web/src/js/__tests__/components/Modes/__snapshots__/RegularSpec.tsx.snap index d9d856e77..3f75142f6 100644 --- a/web/src/js/__tests__/components/Modes/__snapshots__/RegularSpec.tsx.snap +++ b/web/src/js/__tests__/components/Modes/__snapshots__/RegularSpec.tsx.snap @@ -28,6 +28,17 @@ exports[`RegularSpec 1`] = ` tabindex="0" /> +
+
+
+ HTTP(S) proxy listening at 127.0.0.1:8080 and [::1]:8080. +
+
+
@@ -62,9 +73,13 @@ exports[`RegularSpec 2`] = ` />
- port already in use +
+ port already in use +
diff --git a/web/src/js/__tests__/components/__snapshots__/CaptureSetupSpec.tsx.snap b/web/src/js/__tests__/components/__snapshots__/CaptureSetupSpec.tsx.snap deleted file mode 100644 index d37caa1c8..000000000 --- a/web/src/js/__tests__/components/__snapshots__/CaptureSetupSpec.tsx.snap +++ /dev/null @@ -1,42 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CaptureSetup 1`] = ` - -
-

- mitmproxy is running. -

-

- No flows have been recorded yet. -
- Configure your client to use one of the following proxy servers: -

- -
-
-`; diff --git a/web/src/js/components/CaptureSetup.tsx b/web/src/js/components/CaptureSetup.tsx deleted file mode 100644 index 0faef56a3..000000000 --- a/web/src/js/components/CaptureSetup.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import * as React from "react"; -import { useEffect, useRef } from "react"; -import { useAppSelector } from "../ducks"; -import { ServerInfo } from "../ducks/backendState"; -import { formatAddress } from "../utils"; -import QRCode from "qrcode"; - -export default function CaptureSetup() { - const servers = Object.values( - useAppSelector((state) => state.backendState.servers), - ); - - let configure_action_text; - if (servers.length === 0) { - configure_action_text = ""; - } else if (servers.length === 1) { - configure_action_text = - "Configure your client to use the following proxy server:"; - } else { - configure_action_text = - "Configure your client to use one of the following proxy servers:"; - } - - return ( -
-

mitmproxy is running.

-

- No flows have been recorded yet. -
- {configure_action_text} -

-
    - {servers.map((server) => ( -
  • - -
  • - ))} -
- {/* -

You can also start additional servers:

-
    -
  • TODO
  • -
- */} -
- ); -} - -export function ServerDescription({ - description, - listen_addrs, - last_exception, - is_running, - full_spec, - wireguard_conf, -}: ServerInfo) { - const qrCode = useRef(null); - useEffect(() => { - if (wireguard_conf && qrCode.current) - QRCode.toCanvas(qrCode.current, wireguard_conf, { - margin: 0, - scale: 3, - }); - }, [wireguard_conf]); - - let listen_str; - const all_same_port = - listen_addrs.length === 1 || - (listen_addrs.length === 2 && - listen_addrs[0][1] === listen_addrs[1][1]); - const unbound = listen_addrs.every((addr) => - ["::", "0.0.0.0"].includes(addr[0]), - ); - if (all_same_port && unbound) { - listen_str = formatAddress(["*", listen_addrs[0][1]]); - } else { - listen_str = listen_addrs.map(formatAddress).join(" and "); - } - description = description[0].toUpperCase() + description.substr(1); - let desc, icon; - if (last_exception) { - icon = "fa-exclamation text-error"; - desc = ( - <> - {description} ({full_spec}): -
- {last_exception} - - ); - } else if (!is_running) { - icon = "fa-pause text-warning"; - desc = ( - <> - {description} ({full_spec}) - - ); - } else { - icon = "fa-check text-success"; - desc = `${description} listening at ${listen_str}.`; - - if (wireguard_conf) { - desc = ( - <> - {desc} -
-
{wireguard_conf}
- -
- - ); - } - } - return ( - <> - - {desc} - - ); -} diff --git a/web/src/js/components/MainView.tsx b/web/src/js/components/MainView.tsx index 5fece4961..9c639f5df 100644 --- a/web/src/js/components/MainView.tsx +++ b/web/src/js/components/MainView.tsx @@ -3,7 +3,7 @@ import Splitter from "./common/Splitter"; import FlowTable from "./FlowTable"; import FlowView from "./FlowView"; import { useAppSelector } from "../ducks"; -import CaptureSetup from "./CaptureSetup"; +import CaptureSetup from "./Modes/CaptureSetup"; import Modes from "./Modes"; import { Tab } from "../ducks/ui/tabs"; diff --git a/web/src/js/components/Modes/CaptureSetup.tsx b/web/src/js/components/Modes/CaptureSetup.tsx new file mode 100644 index 000000000..fae840592 --- /dev/null +++ b/web/src/js/components/Modes/CaptureSetup.tsx @@ -0,0 +1,99 @@ +import * as React from "react"; +import { useEffect, useRef } from "react"; +import { ServerInfo } from "../../ducks/backendState"; +import { formatAddress } from "../../utils"; +import QRCode from "qrcode"; + +export default function CaptureSetup() { + return ( +
+

mitmproxy is running.

+

+ No flows have been recorded yet. +
+ To start capturing traffic, please configure your settings in + the Capture tab. +

+
+ ); +} + +function ServerDescription({ + description, + listen_addrs, + is_running, + full_spec, + wireguard_conf, + type, +}: ServerInfo) { + const qrCode = useRef(null); + useEffect(() => { + if (wireguard_conf && qrCode.current) + QRCode.toCanvas(qrCode.current, wireguard_conf, { + margin: 0, + scale: 3, + }); + }, [wireguard_conf]); + + let listen_str; + const all_same_port = + listen_addrs.length === 1 || + (listen_addrs.length === 2 && + listen_addrs[0][1] === listen_addrs[1][1]); + const unbound = listen_addrs.every((addr) => + ["::", "0.0.0.0"].includes(addr[0]), + ); + if (all_same_port && unbound) { + listen_str = formatAddress(["*", listen_addrs[0][1]]); + } else { + listen_str = listen_addrs.map(formatAddress).join(" and "); + } + description = description[0].toUpperCase() + description.substr(1); + let desc; + if (!is_running) { + desc = ( + <> +
+ {description} ({full_spec}) +
+ + ); + } else { + desc = ( + <> + {type === "local" ? ( +
{description} is active.
+ ) : ( +
+ {description} listening at {listen_str}. +
+ )} + {wireguard_conf && ( +
+
{wireguard_conf}
+ +
+ )} + + ); + } + return
{desc}
; +} + +export function ServerStatus({ + error, + backendState, +}: { + error?: string; + backendState?: ServerInfo; +}) { + return ( +
+ {error ? ( +
{error}
+ ) : ( + backendState && + )} +
+ ); +} diff --git a/web/src/js/components/Modes/Local.tsx b/web/src/js/components/Modes/Local.tsx index 408f6c90a..3abe91f34 100644 --- a/web/src/js/components/Modes/Local.tsx +++ b/web/src/js/components/Modes/Local.tsx @@ -4,17 +4,21 @@ import { useAppDispatch, useAppSelector } from "../../ducks"; import { setActive, setApplications } from "../../ducks/modes/local"; import ValueEditor from "../editors/ValueEditor"; import { getSpec, LocalState } from "../../modes/local"; +import { ServerStatus } from "./CaptureSetup"; +import { ServerInfo } from "../../ducks/backendState"; export default function Local() { const serverState = useAppSelector((state) => state.modes.local); const backendState = useAppSelector((state) => state.backendState.servers); const servers = serverState.map((server) => { - const error = - server.error || - backendState[getSpec(server)]?.last_exception || - undefined; - return ; + return ( + + ); }); return ( @@ -28,9 +32,17 @@ export default function Local() { ); } -function LocalRow({ server, error }: { server: LocalState; error?: string }) { +function LocalRow({ + server, + backendState, +}: { + server: LocalState; + backendState?: ServerInfo; +}) { const dispatch = useAppDispatch(); + const error = server.error || backendState?.last_exception || undefined; + return (
- {error &&
{error}
} +
); } diff --git a/web/src/js/components/Modes/Regular.tsx b/web/src/js/components/Modes/Regular.tsx index 7a40e08cc..799817ca7 100644 --- a/web/src/js/components/Modes/Regular.tsx +++ b/web/src/js/components/Modes/Regular.tsx @@ -4,17 +4,21 @@ import { useAppDispatch, useAppSelector } from "../../ducks"; import { setListenPort, setActive } from "../../ducks/modes/regular"; import ValueEditor from "../editors/ValueEditor"; import { getSpec, RegularState } from "../../modes/regular"; +import { ServerInfo } from "../../ducks/backendState"; +import { ServerStatus } from "./CaptureSetup"; export default function Regular() { const serverState = useAppSelector((state) => state.modes.regular); const backendState = useAppSelector((state) => state.backendState.servers); const servers = serverState.map((server) => { - const error = - server.error || - backendState[getSpec(server)]?.last_exception || - undefined; - return ; + return ( + + ); }); return ( @@ -31,15 +35,18 @@ export default function Regular() { function RegularRow({ server, - error, + backendState, }: { server: RegularState; error?: string; + backendState?: ServerInfo; }) { const dispatch = useAppDispatch(); server.listen_host && console.warn("TODO: implement listen_host"); + const error = server.error || backendState?.last_exception || undefined; + return (
- {error &&
{error}
} +
); } diff --git a/web/src/js/components/Modes/Reverse.tsx b/web/src/js/components/Modes/Reverse.tsx index f8efcffa3..c6bd28c6f 100644 --- a/web/src/js/components/Modes/Reverse.tsx +++ b/web/src/js/components/Modes/Reverse.tsx @@ -2,11 +2,13 @@ import * as React from "react"; import ReverseToggleRow from "./ReverseToggleRow"; import { useAppDispatch, useAppSelector } from "../../ducks"; import { addServer } from "../../ducks/modes/reverse"; +import { getSpec } from "../../modes/reverse"; export default function Reverse() { const dispatch = useAppDispatch(); const servers = useAppSelector((state) => state.modes.reverse); + const backendState = useAppSelector((state) => state.backendState.servers); return (
@@ -16,15 +18,19 @@ export default function Reverse() {

{servers.map((server) => ( - + ))} -
-
dispatch(addServer())} - > - Add - additional server +
dispatch(addServer())} + > + + Add additional server +
); diff --git a/web/src/js/components/Modes/ReverseToggleRow.tsx b/web/src/js/components/Modes/ReverseToggleRow.tsx index 00ba45c69..e2ccc8644 100644 --- a/web/src/js/components/Modes/ReverseToggleRow.tsx +++ b/web/src/js/components/Modes/ReverseToggleRow.tsx @@ -13,12 +13,18 @@ import { } from "../../ducks/modes/reverse"; import { ReverseProxyProtocols } from "../../backends/consts"; import { ReverseState } from "../../modes/reverse"; +import { ServerStatus } from "./CaptureSetup"; +import { ServerInfo } from "../../ducks/backendState"; interface ReverseToggleRowProps { server: ReverseState; + backendState?: ServerInfo; } -export default function ReverseToggleRow({ server }: ReverseToggleRowProps) { +export default function ReverseToggleRow({ + server, + backendState, +}: ReverseToggleRowProps) { const dispatch = useAppDispatch(); const protocols = Object.values(ReverseProxyProtocols); @@ -37,6 +43,8 @@ export default function ReverseToggleRow({ server }: ReverseToggleRowProps) { await dispatch(removeServer(server)); }; + const error = server.error || backendState?.last_exception || undefined; + return (
- {server.error && ( -
{server.error}
- )} +
); } diff --git a/web/src/js/components/Modes/Wireguard.tsx b/web/src/js/components/Modes/Wireguard.tsx index 775a7735c..0092fd44c 100644 --- a/web/src/js/components/Modes/Wireguard.tsx +++ b/web/src/js/components/Modes/Wireguard.tsx @@ -3,18 +3,20 @@ import { ModeToggle } from "./ModeToggle"; import { useAppDispatch, useAppSelector } from "../../ducks"; import { getSpec, WireguardState } from "../../modes/wireguard"; import { setActive } from "../../ducks/modes/wireguard"; +import { ServerInfo } from "../../ducks/backendState"; +import { ServerStatus } from "./CaptureSetup"; export default function Wireguard() { const serverState = useAppSelector((state) => state.modes.wireguard); const backendState = useAppSelector((state) => state.backendState.servers); const servers = serverState.map((server) => { - const error = - server.error || - backendState[getSpec(server)]?.last_exception || - undefined; return ( - + ); }); @@ -32,13 +34,15 @@ export default function Wireguard() { function WireGuardRow({ server, - error, + backendState, }: { server: WireguardState; - error?: string; + backendState?: ServerInfo; }) { const dispatch = useAppDispatch(); + const error = server.error || backendState?.last_exception || undefined; + return (
Run WireGuard Server - {error &&
{error}
} +
); }