Feature/wireguard mode (#6959)

* define first components

* Update CHANGELOG.md

* Autofix generated JS files and do not patch them in tests (#6910)

* autofix generated JS files and do not patch them in tests

* autofix: setup python

* [autofix.ci] apply automated fixes

* autofix: setup node

* add missing newline

* fixup

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* Update package-lock.json, bump esbuild (#6915)

update node version, bump esbuild

* Fix clipboard handling in safari (#6917)

* fix clipboard handling in safari

closes #6911, #6909

Co-authored-by: Can Yesilyurt <36952967+canyesilyurt@users.noreply.github.com>

* [autofix.ci] apply automated fixes

* update dependencies

---------

Co-authored-by: Can Yesilyurt <36952967+canyesilyurt@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* define first modes components

* adapt code to reuse checkbox component

* mitmproxy 10.3.1

* reopen main for development

* [autofix.ci] apply automated fixes

* improve mode toggle design

* remove inline style

* release script: add one less newline

* fix zstd decompression (#6921)

* fix zstd decompression (issue #6914)

* add our fix to CHANGELOG

* add explicit read_across_frames=True + move zstd test to test_encoding.py

---------

Co-authored-by: Maximilian Hils <git@maximilianhils.com>

* first attempt to make the modes functional

* [autofix.ci] apply automated fixes

* Update CHANGELOG.md

* web: Upgrade Redux (#6926)

* update redux and fix resulting test and type failures
* update prettier

* refactor code according to review

* [autofix.ci] apply automated fixes

* first prototype regular mode

* [autofix.ci] apply automated fixes

* Use upstream urwid again (#6929)

use upstream urwid again

* change name regular duck

* Add `HttpConnectedHook` and `HttpConnectErrorHook` (#6930)

* Add HttpConnectedHook and HttpConnectErrorHook

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* rewrite updateMode function and error handling regular mode

* remove label component

* add input field to local mode and fix onKeyDown issue

* add dropdown to reverse mode

* [autofix.ci] apply automated fixes

* change defualt string reverse dropdown

* add new logic to handle modes in the duck

* add local mode with no applications

* [autofix.ci] apply automated fixes

* regular mode is now persistent

* forgot recieve event in regular mode

* join receive and update event

* make local mode functional

* make wireguard mode functional

* [autofix.ci] apply automated fixes

* make reverse mode functional

* [autofix.ci] apply automated fixes

* fix bug reverse mode when refreshing

* fix bug local mode

* [autofix.ci] apply automated fixes

* fix old test

* implement first tests

* [autofix.ci] apply automated fixes

* make DNS mode listen for both UDP and TCP (#6912)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* remove wireguard and reverse modes

* change name function to set local applications

* remove error handling

* remove left over

* add some other review changes

* [autofix.ci] apply automated fixes

* release ci: strip "v" prefix from sigstore file

* fix addListen Addr function

* adjust reverse protocol attribute

* create proper method to parse the mode

* adjust passing applications to local mode

* fix onKeyDown listener and add new input field to local mode

* [autofix.ci] apply automated fixes

* remove leftover

* update tests

* [autofix.ci] apply automated fixes

* remove wireguard and reverse files

* remove additional state local mode

* adjust tests local mode

* update tests local mode

* update last tests modes

* [autofix.ci] apply automated fixes

* fix: OSError raised when ipv6 is disabled (#6942)

the function should return None in this case

* use fetchMock instead of jest.mock

this is slightly nicer because we are testing at the application boundary

* duck tests should use action creators and not manually construct actions

* move toggleLocal to fetchMock

* move updateMode and ModeState into utils

this avoids circular imports. utils may not be the perfect place, but much better than the circular imports

* nits

* [autofix.ci] apply automated fixes

* update tests regular and local mode

* [autofix.ci] apply automated fixes

* review changes tests

* [autofix.ci] apply automated fixes

* adjust parseMode issue

* [autofix.ci] apply automated fixes

* add first components for wireguard mode

* fix CI

* fix typo

* add tests to wireguard mode

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Maximilian Hils <git@maximilianhils.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Can Yesilyurt <36952967+canyesilyurt@users.noreply.github.com>
Co-authored-by: mitmproxy release bot <noreply@mitmproxy.org>
Co-authored-by: Andras Spitzer <sendai@swordsaint.net>
Co-authored-by: Gaurav Jain <64748057+errorxyz@users.noreply.github.com>
Co-authored-by: Walt Chen <godsarmycy@gmail.com>
This commit is contained in:
Matteo Luppi 2024-06-26 13:07:27 +02:00 committed by GitHub
parent d9770ad2b1
commit e047e76b22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 219 additions and 0 deletions

View File

@ -0,0 +1,110 @@
import { enableFetchMocks } from "jest-fetch-mock";
import wireguardReducer, {
getMode,
initialState,
toggleWireguard,
} from "../../../ducks/modes/wireguard";
import { TStore } from "../tutils";
import * as options from "../../../ducks/options";
describe("wireguardReducer", () => {
it("should return the initial state", () => {
const state = wireguardReducer(undefined, {});
expect(state).toEqual(initialState);
});
it("should dispatch MODE_WIREGUARD_TOGGLE and updateMode", async () => {
enableFetchMocks();
const store = TStore();
expect(store.getState().modes.wireguard.active).toBe(false);
await store.dispatch(toggleWireguard());
expect(store.getState().modes.wireguard.active).toBe(true);
expect(fetchMock).toHaveBeenCalled();
});
it('should handle RECEIVE_OPTIONS action with data.mode containing "wireguard", an host and a port', () => {
const action = {
type: options.RECEIVE,
data: {
mode: {
value: ["wireguard:/path_example@localhost:8081"],
},
},
};
const newState = wireguardReducer(initialState, action);
expect(newState.active).toBe(true);
expect(newState.listen_host).toBe("localhost");
expect(newState.listen_port).toBe(8081);
expect(newState.path).toBe("/path_example");
});
it('should handle RECEIVE_OPTIONS action with data.mode containing just "wireguard"', () => {
const initialState = {
active: false,
listen_host: "localhost",
listen_port: 8080,
};
const action = {
type: options.RECEIVE,
data: {
mode: {
value: ["wireguard"],
},
},
};
const newState = wireguardReducer(initialState, action);
expect(newState.active).toBe(true);
expect(newState.listen_host).toBe("");
expect(newState.listen_port).toBe("");
expect(newState.path).toBe("");
});
it("should handle RECEIVE_OPTIONS action with data.mode containing another mode", () => {
const initialState = {
active: false,
listen_host: "localhost",
listen_port: 8080,
path: "/path_example",
};
const action = {
type: options.RECEIVE,
data: {
mode: {
value: ["local"],
},
},
};
const newState = wireguardReducer(initialState, action);
expect(newState.active).toBe(false);
expect(newState.listen_host).toBe(initialState.listen_host);
expect(newState.listen_port).toBe(initialState.listen_port);
expect(newState.path).toBe(initialState.path);
});
});
describe("getMode", () => {
it("should return the correct mode string when active", () => {
const modes = {
wireguard: {
active: true,
},
};
const mode = getMode(modes);
expect(JSON.stringify(mode)).toBe(JSON.stringify(["wireguard"]));
});
it("should return an empty string when not active", () => {
const modes = {
wireguard: {
active: false,
path: "/path_example",
listen_host: "localhost",
listen_port: 8080,
},
};
const mode = getMode(modes);
expect(JSON.stringify(mode)).toBe(JSON.stringify([]));
});
});

View File

@ -132,6 +132,9 @@ export const testState: RootState = {
active: false,
applications: "",
},
wireguard: {
active: false,
},
},
};

View File

@ -1,6 +1,7 @@
import * as React from "react";
import Local from "./Modes/Local";
import Regular from "./Modes/Regular";
import Wireguard from "./Modes/Wireguard";
export default function Modes() {
return (
@ -12,6 +13,7 @@ export default function Modes() {
<div className="modes-container">
<Regular />
<Local />
<Wireguard />
</div>
</div>
);

View File

@ -0,0 +1,27 @@
import * as React from "react";
import { ModeToggle } from "./ModeToggle";
import { useAppDispatch, useAppSelector } from "../../ducks";
import { toggleWireguard } from "../../ducks/modes/wireguard";
export default function Wireguard() {
const dispatch = useAppDispatch();
const { active, error } = useAppSelector((state) => state.modes.wireguard);
return (
<div>
<h4 className="mode-title">WireGuard Server</h4>
<p className="mode-description">
Start a WireGuard server and connect an external device for
transparent proxying.
</p>
<ModeToggle
value={active}
onChange={() => dispatch(toggleWireguard())}
>
Run WireGuard Server
</ModeToggle>
{error && <div className="mode-error text-danger">{error}</div>}
</div>
);
}

View File

@ -1,10 +1,12 @@
import { combineReducers } from "redux";
import regularReducer from "./modes/regular";
import localReducer from "./modes/local";
import wireguardReducer from "./modes/wireguard";
const modes = combineReducers({
regular: regularReducer,
local: localReducer,
wireguard: wireguardReducer,
//add new modes here
});

View File

@ -1,5 +1,6 @@
import { getMode as getRegularModeConfig } from "./regular";
import { getMode as getLocalModeConfig } from "./local";
import { getMode as getWireguardModeConfig } from "./wireguard";
import { fetchApi, rpartition } from "../../utils";
export interface ModeState {
@ -17,6 +18,7 @@ export const updateMode = () => {
const activeModes: string[] = [
...getRegularModeConfig(modes),
...getLocalModeConfig(modes),
...getWireguardModeConfig(modes),
//add new modes here
];
const response = await fetchApi.put("/options", {

View File

@ -0,0 +1,73 @@
import {
RECEIVE as RECEIVE_OPTIONS,
UPDATE as UPDATE_OPTIONS,
} from "../options";
import {
ModeState,
includeModeState,
updateMode,
getModesOfType,
} from "./utils";
export const MODE_WIREGUARD_TOGGLE = "MODE_WIREGUARD_TOGGLE";
interface WireguardState extends ModeState {
path?: string;
}
export const initialState: WireguardState = {
active: false,
path: "",
};
export const getMode = (modes) => {
const wireguardMode = modes.wireguard;
return includeModeState("wireguard", wireguardMode);
};
export const toggleWireguard = () => {
return async (dispatch) => {
dispatch({ type: MODE_WIREGUARD_TOGGLE });
const result = await dispatch(updateMode());
if (!result.success) {
//TODO: handle error
}
};
};
const wireguardReducer = (state = initialState, action): WireguardState => {
switch (action.type) {
case MODE_WIREGUARD_TOGGLE:
return {
...state,
active: !state.active,
};
case UPDATE_OPTIONS:
case RECEIVE_OPTIONS:
if (action.data && action.data.mode) {
const currentModeConfig = getModesOfType(
"wireguard",
action.data.mode.value,
)[0];
const isActive = currentModeConfig !== undefined;
return {
...state,
active: isActive,
path: isActive ? currentModeConfig.data : state.path,
listen_host: isActive
? currentModeConfig.listen_host
: state.listen_host,
listen_port: isActive
? (currentModeConfig.listen_port as number)
: state.listen_port,
};
}
return state;
default:
return state;
}
};
export default wireguardReducer;