The Gui Structure of MITM Proxy
2023-04-28
TL;DR
Starting with release 1.6, Tauri + yew was chosen instead of Egui + Eframe. Tauri is a modern web-based framework for creating desktop applications. It is built on top of the Rust programming language and uses the native capabilities of the operating system to render the application. Tauri is a great choice for creating desktop applications because it is fast, secure, and easy to use.
Toc
[
Hide]
Dependecies
this is the content of Cargo.toml file:
[package]
name = "tauri-ui-ui"
version = "0.0.0"
edition = "2021"
[dependencies]
yew = { version = "0.20", features = ["csr"] }
stylist = { version = "0.12.0", features = ["yew_use_style"] }
serde = { version = "1.0", features = ["derive"] }
wasm-bindgen = "0.2"
gloo-utils = { version = "0.1", features = ["serde"]}
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
web-sys = { version = "0.3", features = ["MediaQueryList", "Window", "HtmlSelectElement", "HtmlOptionElement"] }
proxyapi_models = {path = "../proxyapi_models"}
http = "0.2"
url = "2.3.1"
yew is a very modern rust framework for building frontend web apps using WebAssembly. It is a component-based framework which makes it easy to create interactive UIs.
stylist is a CSS solution for yew, it makes easy to style Yew components.
serde is a Rust library usefull to serialize and deserialize data structures in rust. I'm still not used to use it but it is pretty fundamental to manage Json, Yaml and other common structures.
wasm-bindgen and wasm-bindgen-futures are modules that facilitate high-level interactions between Wasm modules and Javascript, they are foundamental to use yew.
js-sys is built on top of wasm-bindgen and it is a binding to Javascript's standard.
gloo-utils is a crate that provides a number of utility for working with web platform, it is built on top of web-sys create, which provides access to the web platform's APIs.
web-sys provides a binding to all APIs that browsers provide on the web. It does not include Javascript APIs that are guaranteed to exist in all standards-compliant ECMAScript environment, such as Array, Date etc... Bindings for these APIs can be found in the Js-sys crate.
http and url are usefull to build and parse http and url requests and respnses.
The structure of a Tauri APP
Frontend Api
tauri-ui/src is the directory where Yew Frontend code is located, it contains components and api.rs to listen and emit events as:
- start_proxy() starts the proxy server on the specified address
- stop_proxy() stops the proxy server
- listening_proxy_event() listens for events from the proxy server and calls the specified callback when an event is received
Components
tauri-ui/src/components contains all yew components, the logic is similar to a Vue component, in each file are managed the style, the logic and the HTML structure. This is an example of title_bar component:
use stylist::yew::use_style;
use yew::prelude::*;
#[function_component(ThemeButton)]
fn theme_button() -> Html {
let is_dark = use_state(|| {
let mut is_dark = false;
if let Some(window) = web_sys::window() {
if let Ok(Some(media)) = window.match_media("(prefers-color-scheme: dark)") {
is_dark = media.matches();
}
}
is_dark
});
let (data_theme, btn_text) = match *is_dark {
true => ("dark", "🔆"),
false => ("light", "🌙"),
};
if let Some(window) = web_sys::window() {
if let Some(document) = window.document() {
if let Some(body) = document.body() {
body.set_attribute("data-theme", data_theme).unwrap();
}
}
}
let onclick = {
let is_dark = is_dark;
Callback::from(move |_| is_dark.set(!*is_dark))
};
html! {
<button {onclick} ~innerText={btn_text} />
}
}
#[function_component(TitleBar)]
pub fn title_bar() -> Html {
let style = use_style!(
r#"
display: flex;
flex-flow: row;
align-items: center;
justify-content:space-between;
position: relative;
h1{
right:0;
left:0;
text-align:center;
font-size: 1.2rem;
font-weight: normal;
flex: none;
margin:auto;
text-transform: uppercase;
font-size: 1rem;
font-weight: bold;
position:absolute;
margin:auto;
z-index:-1;
}
button{
background: var(--bg-input);
border: 0px;
width:45px;
text-align:center;
height: 45px;
line-height:42px;
border-radius: 100px;
color: white;
box-shadow: var(--box-shadow);
margin-left:auto;
text-shadow: 2px 2px 8px #00000033;
cursor:pointer;
}
"#
);
html! {
<div class={style}>
<h1 ~innerText="Man In The Middle Proxy" />
<ThemeButton />
</div>
}
}
The Link between frontend and backend
tauri-ui/src-tauri/ contains backend of the Tauri app with all stuffs to interact with proxyapi, the actual backend of the MITM proxy.
Filter requests by Method
The filter request is managed in request component
all variants are stored in a slice of &str.
const OPTIONS: [&str; 10] = [
"POST", "GET", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT", "TRACE", "OTHERS",
];
//snip
pub fn filter_request(method: String, filters: &[String]) -> bool {
filters.contains(&method)
|| (!OPTIONS.contains(&method.as_str()) && filters.contains(&"OTHERS".to_string()))
}
Each row is shown only if filter_request return true, filter_request receive a String that represent the method and a slice of String that represent filter criteria, it return true only if the filters contains the method or if the filter is set to OTHER.
Dark and Light Theme Management
Theme is managed by a simple state that change the color-scheme of the entire app:
let is_dark = use_state(|| {
let mut is_dark = false;
if let Some(window) = web_sys::window() {
if let Ok(Some(media)) = window.match_media("(prefers-color-scheme: dark)") {
is_dark = media.matches();
}
}
is_dark
});
the color scheme is a sort of CSS Variable, when it is set to false style.css uses some colors, when is set to true uses others:
[data-theme="light"] {
--bg-color: #dee5f3;
--bg-color-secondary: #efefef;
/* snipp */
--little-contrast:#e4e4e4;
--bg-input: #fff;
--shadow-color: 220deg 47% 85%;
}
[data-theme="dark"] {
--bg-color: #121212;
--bg-color-secondary: #1d1d1d;
/* snipp */
--little-contrast:#2a2a2a;
--bg-input: #373737;
--shadow-color: 240deg 4% 14%;
}