summaryrefslogtreecommitdiffhomepage
path: root/gui/src/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'gui/src/renderer')
-rw-r--r--gui/src/renderer/app.tsx4
-rw-r--r--gui/src/renderer/components/AppRouter.tsx4
-rw-r--r--gui/src/renderer/components/WireguardSettings.tsx629
-rw-r--r--gui/src/renderer/containers/WireguardSettingsPage.tsx115
-rw-r--r--gui/src/renderer/lib/utilityHooks.ts2
5 files changed, 373 insertions, 381 deletions
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index 7d269b9bdd..9e2130ff1f 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -454,11 +454,11 @@ export default class AppRenderer {
await IpcRendererEventChannel.settings.setOpenVpnMssfix(mssfix);
}
- public async setWireguardMtu(mtu?: number) {
+ public setWireguardMtu = async (mtu?: number) => {
const actions = this.reduxActions;
actions.settings.updateWireguardMtu(mtu);
await IpcRendererEventChannel.settings.setWireguardMtu(mtu);
- }
+ };
public setAutoConnect(autoConnect: boolean) {
IpcRendererEventChannel.guiSettings.setAutoConnect(autoConnect);
diff --git a/gui/src/renderer/components/AppRouter.tsx b/gui/src/renderer/components/AppRouter.tsx
index 75892805e9..4791faecb6 100644
--- a/gui/src/renderer/components/AppRouter.tsx
+++ b/gui/src/renderer/components/AppRouter.tsx
@@ -8,7 +8,6 @@ import OpenVPNSettingsPage from '../containers/OpenVPNSettingsPage';
import ProblemReportPage from '../containers/ProblemReportPage';
import SelectLanguagePage from '../containers/SelectLanguagePage';
import SelectLocationPage from '../containers/SelectLocationPage';
-import WireguardSettingsPage from '../containers/WireguardSettingsPage';
import withAppContext, { IAppContext } from '../context';
import { IHistoryProps, ITransitionSpecification, transitions, withHistory } from '../lib/history';
import { RoutePath } from '../lib/routes';
@@ -30,6 +29,7 @@ import Support from './Support';
import TooManyDevices from './TooManyDevices';
import TransitionContainer, { TransitionView } from './TransitionContainer';
import VpnSettings from './VpnSettings';
+import WireguardSettings from './WireguardSettings';
interface IAppRoutesState {
currentLocation: IHistoryProps['history']['location'];
@@ -92,7 +92,7 @@ class AppRouter extends React.Component<IHistoryProps & IAppContext, IAppRoutesS
<Route exact path={RoutePath.accountSettings} component={AccountPage} />
<Route exact path={RoutePath.interfaceSettings} component={InterfaceSettings} />
<Route exact path={RoutePath.vpnSettings} component={VpnSettings} />
- <Route exact path={RoutePath.wireguardSettings} component={WireguardSettingsPage} />
+ <Route exact path={RoutePath.wireguardSettings} component={WireguardSettings} />
<Route exact path={RoutePath.openVpnSettings} component={OpenVPNSettingsPage} />
<Route exact path={RoutePath.splitTunneling} component={SplitTunnelingSettings} />
<Route exact path={RoutePath.support} component={Support} />
diff --git a/gui/src/renderer/components/WireguardSettings.tsx b/gui/src/renderer/components/WireguardSettings.tsx
index d0a22c7e87..d11d57e0fc 100644
--- a/gui/src/renderer/components/WireguardSettings.tsx
+++ b/gui/src/renderer/components/WireguardSettings.tsx
@@ -1,16 +1,23 @@
-import * as React from 'react';
+import { useCallback, useMemo } from 'react';
import { sprintf } from 'sprintf-js';
import styled from 'styled-components';
-import { strings } from '../../config.json';
+import { colors, strings } from '../../config.json';
import { IpVersion } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
+import log from '../../shared/logging';
+import { useAppContext } from '../context';
+import { createWireguardRelayUpdater } from '../lib/constraint-updater';
+import { useHistory } from '../lib/history';
+import { useBoolean } from '../lib/utilityHooks';
+import { useSelector } from '../redux/store';
import * as AppButton from './AppButton';
import { AriaDescription, AriaInput, AriaInputGroup, AriaLabel } from './AriaGroup';
import * as Cell from './cell';
import Selector, { ISelectorItem } from './cell/Selector';
+import { InfoIcon } from './InfoButton';
import { BackAction } from './KeyboardNavigation';
-import { Layout, SettingsContainer } from './Layout';
+import { Container, Layout } from './Layout';
import { ModalAlert, ModalAlertType } from './Modal';
import {
NavigationBar,
@@ -20,7 +27,6 @@ import {
TitleBarItem,
} from './NavigationBar';
import SettingsHeader, { HeaderTitle } from './SettingsHeader';
-import Switch from './Switch';
const MIN_WIREGUARD_MTU_VALUE = 1280;
const MAX_WIREGUARD_MTU_VALUE = 1420;
@@ -33,305 +39,406 @@ function mapPortToSelectorItem(value: number): ISelectorItem<number> {
return { label: value.toString(), value };
}
-export const StyledNavigationScrollbars = styled(NavigationScrollbars)({
+export const StyledContainer = styled(Container)({
+ backgroundColor: colors.darkBlue,
+});
+
+export const StyledContent = styled.div({
+ display: 'flex',
+ flexDirection: 'column',
flex: 1,
+ marginBottom: '2px',
+});
+
+export const StyledCellIcon = styled(Cell.UntintedIcon)({
+ marginRight: '8px',
+});
+
+export const StyledInfoIcon = styled(InfoIcon)({
+ marginRight: '16px',
});
export const StyledSelectorContainer = styled.div({
flex: 0,
});
-export const StyledSelectorForFooter = (styled(Selector)({
- marginBottom: 0,
-}) as unknown) as new <T>() => Selector<T>;
+export default function WireguardSettings() {
+ const { pop } = useHistory();
-interface IProps {
- wireguard: { port?: number; ipVersion?: IpVersion };
- wireguardMtu?: number;
- wireguardMultihop: boolean;
- setWireguardMtu: (value: number | undefined) => void;
- setWireguardMultihop: (value: boolean) => void;
- setWireguardPort: (port?: number) => void;
- setWireguardIpVersion: (ipVersion?: IpVersion) => void;
- onClose: () => void;
-}
+ return (
+ <BackAction action={pop}>
+ <Layout>
+ <StyledContainer>
+ <NavigationContainer>
+ <NavigationBar>
+ <NavigationItems>
+ <TitleBarItem>
+ {sprintf(
+ // TRANSLATORS: Title label in navigation bar
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
+ messages.pgettext('wireguard-settings-nav', '%(wireguard)s settings'),
+ { wireguard: strings.wireguard },
+ )}
+ </TitleBarItem>
+ </NavigationItems>
+ </NavigationBar>
-interface IState {
- showMultihopConfirmationDialog: boolean;
-}
+ <NavigationScrollbars>
+ <SettingsHeader>
+ <HeaderTitle>
+ {sprintf(
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
+ messages.pgettext('wireguard-settings-view', '%(wireguard)s settings'),
+ { wireguard: strings.wireguard },
+ )}
+ </HeaderTitle>
+ </SettingsHeader>
-export default class WireguardSettings extends React.Component<IProps, IState> {
- public state = { showMultihopConfirmationDialog: false };
+ <StyledContent>
+ <Cell.Group>
+ <PortSelector />
+ </Cell.Group>
+
+ <Cell.Group>
+ <MultihopSetting />
+ </Cell.Group>
- private multihopRef = React.createRef<Switch>();
+ <Cell.Group>
+ <IpVersionSetting />
+ </Cell.Group>
- private wireguardPortItems: Array<ISelectorItem<OptionalPort>>;
- private wireguardIpVersionItems: Array<ISelectorItem<OptionalIpVersion>>;
+ <Cell.Group>
+ <MtuSetting />
+ </Cell.Group>
+ </StyledContent>
+ </NavigationScrollbars>
+ </NavigationContainer>
+ </StyledContainer>
+ </Layout>
+ </BackAction>
+ );
+}
- constructor(props: IProps) {
- super(props);
+function PortSelector() {
+ const relaySettings = useSelector((state) => state.settings.relaySettings);
+ const { updateRelaySettings } = useAppContext();
+ const wireguardPortItems = useMemo(() => {
const automaticPort: ISelectorItem<OptionalPort> = {
label: messages.gettext('Automatic'),
value: undefined,
};
- this.wireguardPortItems = [automaticPort].concat(
- WIREUGARD_UDP_PORTS.map(mapPortToSelectorItem),
- );
-
- this.wireguardIpVersionItems = [
- {
- label: messages.gettext('Automatic'),
- value: undefined,
- },
- {
- label: messages.gettext('IPv4'),
- value: 'ipv4',
- },
- {
- label: messages.gettext('IPv6'),
- value: 'ipv6',
- },
- ];
- }
-
- public render() {
- return (
- <BackAction action={this.props.onClose}>
- <Layout>
- <SettingsContainer>
- <NavigationContainer>
- <NavigationBar>
- <NavigationItems>
- <TitleBarItem>
- {sprintf(
- // TRANSLATORS: Title label in navigation bar
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
- messages.pgettext('wireguard-settings-nav', '%(wireguard)s settings'),
- { wireguard: strings.wireguard },
- )}
- </TitleBarItem>
- </NavigationItems>
- </NavigationBar>
+ return [automaticPort].concat(WIREUGARD_UDP_PORTS.map(mapPortToSelectorItem));
+ }, []);
- <StyledNavigationScrollbars>
- <SettingsHeader>
- <HeaderTitle>
- {sprintf(
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
- messages.pgettext('wireguard-settings-view', '%(wireguard)s settings'),
- { wireguard: strings.wireguard },
- )}
- </HeaderTitle>
- </SettingsHeader>
+ const port = useMemo(() => {
+ const port = 'normal' in relaySettings ? relaySettings.normal.wireguard.port : undefined;
+ return port === 'any' ? undefined : port;
+ }, [relaySettings]);
- <Cell.Group>
- <AriaInputGroup>
- <StyledSelectorContainer>
- <StyledSelectorForFooter
- // TRANSLATORS: The title for the WireGuard port selector.
- title={messages.pgettext('wireguard-settings-view', 'Port')}
- values={this.wireguardPortItems}
- value={this.props.wireguard.port}
- onSelect={this.props.setWireguardPort}
- />
- </StyledSelectorContainer>
- <Cell.Footer>
- <AriaDescription>
- <Cell.FooterText>
- {
- // TRANSLATORS: The hint displayed below the WireGuard port selector.
- messages.pgettext(
- 'wireguard-settings-view',
- 'The automatic setting will randomly choose from a wide range of ports.',
- )
- }
- </Cell.FooterText>
- </AriaDescription>
- </Cell.Footer>
- </AriaInputGroup>
- </Cell.Group>
+ const setWireguardPort = useCallback(
+ async (port?: number) => {
+ const relayUpdate = createWireguardRelayUpdater(relaySettings)
+ .tunnel.wireguard((wireguard) => {
+ if (port) {
+ wireguard.port.exact(port);
+ } else {
+ wireguard.port.any();
+ }
+ })
+ .build();
+ try {
+ await updateRelaySettings(relayUpdate);
+ } catch (e) {
+ const error = e as Error;
+ log.error('Failed to update relay settings', error.message);
+ }
+ },
+ [relaySettings],
+ );
- <Cell.Group>
- <AriaInputGroup>
- <Cell.Container>
- <AriaLabel>
- <Cell.InputLabel>
- {
- // TRANSLATORS: The label next to the multihop settings toggle.
- messages.pgettext('vpn-settings-view', 'Enable multihop')
- }
- </Cell.InputLabel>
- </AriaLabel>
- <AriaInput>
- <Cell.Switch
- ref={this.multihopRef}
- isOn={this.props.wireguardMultihop}
- onChange={this.setWireguardMultihop}
- />
- </AriaInput>
- </Cell.Container>
- <Cell.Footer>
- <AriaDescription>
- <Cell.FooterText>
- {sprintf(
- // TRANSLATORS: Description for multihop settings toggle.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
- messages.pgettext(
- 'vpn-settings-view',
- 'Increases anonymity by routing your traffic into one %(wireguard)s server and out another, making it harder to trace.',
- ),
- { wireguard: strings.wireguard },
- )}
- </Cell.FooterText>
- </AriaDescription>
- </Cell.Footer>
- </AriaInputGroup>
- </Cell.Group>
+ return (
+ <AriaInputGroup>
+ <StyledSelectorContainer>
+ <Selector
+ // TRANSLATORS: The title for the WireGuard port selector.
+ title={messages.pgettext('wireguard-settings-view', 'Port')}
+ values={wireguardPortItems}
+ value={port}
+ onSelect={setWireguardPort}
+ />
+ </StyledSelectorContainer>
+ <Cell.Footer>
+ <AriaDescription>
+ <Cell.FooterText>
+ {
+ // TRANSLATORS: The hint displayed below the WireGuard port selector.
+ messages.pgettext(
+ 'wireguard-settings-view',
+ 'The automatic setting will randomly choose from a wide range of ports.',
+ )
+ }
+ </Cell.FooterText>
+ </AriaDescription>
+ </Cell.Footer>
+ </AriaInputGroup>
+ );
+}
- <Cell.Group>
- <AriaInputGroup>
- <StyledSelectorContainer>
- <StyledSelectorForFooter
- // TRANSLATORS: The title for the WireGuard IP version selector.
- title={messages.pgettext('wireguard-settings-view', 'IP version')}
- values={this.wireguardIpVersionItems}
- value={this.props.wireguard.ipVersion}
- onSelect={this.props.setWireguardIpVersion}
- />
- </StyledSelectorContainer>
- <Cell.Footer>
- <AriaDescription>
- <Cell.FooterText>
- {sprintf(
- // TRANSLATORS: The hint displayed below the WireGuard IP version selector.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
- messages.pgettext(
- 'wireguard-settings-view',
- 'This allows access to %(wireguard)s for devices that only support IPv6.',
- ),
- { wireguard: strings.wireguard },
- )}
- </Cell.FooterText>
- </AriaDescription>
- </Cell.Footer>
- </AriaInputGroup>
- </Cell.Group>
+function MultihopSetting() {
+ const relaySettings = useSelector((state) => state.settings.relaySettings);
+ const { updateRelaySettings } = useAppContext();
- <Cell.Group>
- <AriaInputGroup>
- <Cell.Container>
- <AriaLabel>
- <Cell.InputLabel>
- {messages.pgettext('wireguard-settings-view', 'MTU')}
- </Cell.InputLabel>
- </AriaLabel>
- <AriaInput>
- <Cell.AutoSizingTextInput
- value={this.props.wireguardMtu ? this.props.wireguardMtu.toString() : ''}
- inputMode={'numeric'}
- maxLength={4}
- placeholder={messages.gettext('Default')}
- onSubmitValue={this.onWireguardMtuSubmit}
- validateValue={WireguardSettings.wireguarMtuIsValid}
- submitOnBlur={true}
- modifyValue={WireguardSettings.removeNonNumericCharacters}
- />
- </AriaInput>
- </Cell.Container>
- <Cell.Footer>
- <AriaDescription>
- <Cell.FooterText>
- {sprintf(
- // TRANSLATORS: The hint displayed below the WireGuard MTU input field.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
- // TRANSLATORS: %(max)d - the maximum possible wireguard mtu value
- // TRANSLATORS: %(min)d - the minimum possible wireguard mtu value
- messages.pgettext(
- 'wireguard-settings-view',
- 'Set %(wireguard)s MTU value. Valid range: %(min)d - %(max)d.',
- ),
- {
- wireguard: strings.wireguard,
- min: MIN_WIREGUARD_MTU_VALUE,
- max: MAX_WIREGUARD_MTU_VALUE,
- },
- )}
- </Cell.FooterText>
- </AriaDescription>
- </Cell.Footer>
- </AriaInputGroup>
- </Cell.Group>
- </StyledNavigationScrollbars>
- </NavigationContainer>
- </SettingsContainer>
+ const multihop = 'normal' in relaySettings ? relaySettings.normal.wireguard.useMultihop : false;
- {this.renderMultihopConfirmation()}
- </Layout>
- </BackAction>
- );
- }
+ const [confirmationDialogVisible, showConfirmationDialog, hideConfirmationDialog] = useBoolean();
- private static removeNonNumericCharacters(value: string) {
- return value.replace(/[^0-9]/g, '');
- }
+ const setMultihopImpl = useCallback(
+ async (enabled: boolean) => {
+ const relayUpdate = createWireguardRelayUpdater(relaySettings)
+ .tunnel.wireguard((wireguard) => wireguard.useMultihop(enabled))
+ .build();
+ try {
+ await updateRelaySettings(relayUpdate);
+ } catch (e) {
+ const error = e as Error;
+ log.error('Failed to update WireGuard multihop settings', error.message);
+ }
+ },
+ [relaySettings, updateRelaySettings],
+ );
- private onWireguardMtuSubmit = (value: string) => {
- const parsedValue = value === '' ? undefined : parseInt(value, 10);
- if (WireguardSettings.wireguarMtuIsValid(value)) {
- this.props.setWireguardMtu(parsedValue);
- }
- };
+ const setMultihop = useCallback(
+ async (newValue: boolean) => {
+ if (newValue) {
+ showConfirmationDialog();
+ } else {
+ await setMultihopImpl(false);
+ }
+ },
+ [setMultihopImpl],
+ );
- private static wireguarMtuIsValid(mtu: string): boolean {
- const parsedMtu = mtu ? parseInt(mtu) : undefined;
- return (
- parsedMtu === undefined ||
- (parsedMtu >= MIN_WIREGUARD_MTU_VALUE && parsedMtu <= MAX_WIREGUARD_MTU_VALUE)
- );
- }
+ const confirmMultihop = useCallback(async () => {
+ await setMultihopImpl(true);
+ hideConfirmationDialog();
+ }, [setMultihopImpl]);
- private renderMultihopConfirmation = () => {
- return (
+ return (
+ <>
+ <AriaInputGroup>
+ <Cell.Container>
+ <AriaLabel>
+ <Cell.InputLabel>
+ {
+ // TRANSLATORS: The label next to the multihop settings toggle.
+ messages.pgettext('vpn-settings-view', 'Enable multihop')
+ }
+ </Cell.InputLabel>
+ </AriaLabel>
+ <AriaInput>
+ <Cell.Switch isOn={multihop} onChange={setMultihop} />
+ </AriaInput>
+ </Cell.Container>
+ <Cell.Footer>
+ <AriaDescription>
+ <Cell.FooterText>
+ {sprintf(
+ // TRANSLATORS: Description for multihop settings toggle.
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
+ messages.pgettext(
+ 'vpn-settings-view',
+ 'Increases anonymity by routing your traffic into one %(wireguard)s server and out another, making it harder to trace.',
+ ),
+ { wireguard: strings.wireguard },
+ )}
+ </Cell.FooterText>
+ </AriaDescription>
+ </Cell.Footer>
+ </AriaInputGroup>
<ModalAlert
- isOpen={this.state.showMultihopConfirmationDialog}
+ isOpen={confirmationDialogVisible}
type={ModalAlertType.info}
message={
// TRANSLATORS: Warning text in a dialog that is displayed after a setting is toggled.
messages.gettext('This setting increases latency. Use only if needed.')
}
buttons={[
- <AppButton.RedButton key="confirm" onClick={this.confirmWireguardMultihop}>
+ <AppButton.RedButton key="confirm" onClick={confirmMultihop}>
{messages.gettext('Enable anyway')}
</AppButton.RedButton>,
- <AppButton.BlueButton key="back" onClick={this.hideWireguardMultihopConfirmationDialog}>
+ <AppButton.BlueButton key="back" onClick={hideConfirmationDialog}>
{messages.gettext('Back')}
</AppButton.BlueButton>,
]}
- close={this.hideWireguardMultihopConfirmationDialog}></ModalAlert>
- );
- };
+ close={hideConfirmationDialog}
+ />
+ </>
+ );
+}
+
+function IpVersionSetting() {
+ const { updateRelaySettings } = useAppContext();
+ const relaySettings = useSelector((state) => state.settings.relaySettings);
+ const ipVersion = useMemo(() => {
+ const ipVersion =
+ 'normal' in relaySettings ? relaySettings.normal.wireguard.ipVersion : undefined;
+ return ipVersion === 'any' ? undefined : ipVersion;
+ }, [relaySettings]);
+
+ const ipVersionItems: ISelectorItem<OptionalIpVersion>[] = useMemo(
+ () => [
+ {
+ label: messages.gettext('Automatic'),
+ value: undefined,
+ },
+ {
+ label: messages.gettext('IPv4'),
+ value: 'ipv4',
+ },
+ {
+ label: messages.gettext('IPv6'),
+ value: 'ipv6',
+ },
+ ],
+ [],
+ );
+
+ const setIpVersion = useCallback(
+ async (ipVersion?: IpVersion) => {
+ const relayUpdate = createWireguardRelayUpdater(relaySettings)
+ .tunnel.wireguard((wireguard) => {
+ if (ipVersion) {
+ wireguard.ipVersion.exact(ipVersion);
+ } else {
+ wireguard.ipVersion.any();
+ }
+ })
+ .build();
+ try {
+ await updateRelaySettings(relayUpdate);
+ } catch (e) {
+ const error = e as Error;
+ log.error('Failed to update relay settings', error.message);
+ }
+ },
+ [relaySettings, updateRelaySettings],
+ );
+
+ return (
+ <AriaInputGroup>
+ <StyledSelectorContainer>
+ <Selector
+ // TRANSLATORS: The title for the WireGuard IP version selector.
+ title={messages.pgettext('wireguard-settings-view', 'IP version')}
+ values={ipVersionItems}
+ value={ipVersion}
+ onSelect={setIpVersion}
+ />
+ </StyledSelectorContainer>
+ <Cell.Footer>
+ <AriaDescription>
+ <Cell.FooterText>
+ {sprintf(
+ // TRANSLATORS: The hint displayed below the WireGuard IP version selector.
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
+ messages.pgettext(
+ 'wireguard-settings-view',
+ 'This allows access to %(wireguard)s for devices that only support IPv6.',
+ ),
+ { wireguard: strings.wireguard },
+ )}
+ </Cell.FooterText>
+ </AriaDescription>
+ </Cell.Footer>
+ </AriaInputGroup>
+ );
+}
+
+function removeNonNumericCharacters(value: string) {
+ return value.replace(/[^0-9]/g, '');
+}
+
+function mtuIsValid(mtu: string): boolean {
+ const parsedMtu = mtu ? parseInt(mtu) : undefined;
+ return (
+ parsedMtu === undefined ||
+ (parsedMtu >= MIN_WIREGUARD_MTU_VALUE && parsedMtu <= MAX_WIREGUARD_MTU_VALUE)
+ );
+}
+
+function MtuSetting() {
+ const { setWireguardMtu: setWireguardMtuImpl } = useAppContext();
+ const mtu = useSelector((state) => state.settings.wireguard.mtu);
- private setWireguardMultihop = (newValue: boolean) => {
- if (newValue) {
- this.setState({ showMultihopConfirmationDialog: true });
- } else {
- this.props.setWireguardMultihop(false);
- }
- };
+ const setMtu = useCallback(
+ async (mtu?: number) => {
+ try {
+ await setWireguardMtuImpl(mtu);
+ } catch (e) {
+ const error = e as Error;
+ log.error('Failed to update mtu value', error.message);
+ }
+ },
+ [setWireguardMtuImpl],
+ );
- private hideWireguardMultihopConfirmationDialog = () => {
- this.setState({ showMultihopConfirmationDialog: false });
- };
+ const onSubmit = useCallback(
+ async (value: string) => {
+ const parsedValue = value === '' ? undefined : parseInt(value, 10);
+ if (mtuIsValid(value)) {
+ await setMtu(parsedValue);
+ }
+ },
+ [setMtu],
+ );
- private confirmWireguardMultihop = () => {
- this.setState({ showMultihopConfirmationDialog: false });
- this.props.setWireguardMultihop(true);
- };
+ return (
+ <AriaInputGroup>
+ <Cell.Container>
+ <AriaLabel>
+ <Cell.InputLabel>{messages.pgettext('wireguard-settings-view', 'MTU')}</Cell.InputLabel>
+ </AriaLabel>
+ <AriaInput>
+ <Cell.AutoSizingTextInput
+ value={mtu ? mtu.toString() : ''}
+ inputMode={'numeric'}
+ maxLength={4}
+ placeholder={messages.gettext('Default')}
+ onSubmitValue={onSubmit}
+ validateValue={mtuIsValid}
+ submitOnBlur={true}
+ modifyValue={removeNonNumericCharacters}
+ />
+ </AriaInput>
+ </Cell.Container>
+ <Cell.Footer>
+ <AriaDescription>
+ <Cell.FooterText>
+ {sprintf(
+ // TRANSLATORS: The hint displayed below the WireGuard MTU input field.
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(wireguard)s - Will be replaced with the string "WireGuard"
+ // TRANSLATORS: %(max)d - the maximum possible wireguard mtu value
+ // TRANSLATORS: %(min)d - the minimum possible wireguard mtu value
+ messages.pgettext(
+ 'wireguard-settings-view',
+ 'Set %(wireguard)s MTU value. Valid range: %(min)d - %(max)d.',
+ ),
+ {
+ wireguard: strings.wireguard,
+ min: MIN_WIREGUARD_MTU_VALUE,
+ max: MAX_WIREGUARD_MTU_VALUE,
+ },
+ )}
+ </Cell.FooterText>
+ </AriaDescription>
+ </Cell.Footer>
+ </AriaInputGroup>
+ );
}
diff --git a/gui/src/renderer/containers/WireguardSettingsPage.tsx b/gui/src/renderer/containers/WireguardSettingsPage.tsx
deleted file mode 100644
index 6217c723d2..0000000000
--- a/gui/src/renderer/containers/WireguardSettingsPage.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-import { connect } from 'react-redux';
-
-import { IpVersion } from '../../shared/daemon-rpc-types';
-import log from '../../shared/logging';
-import WireguardSettings from '../components/WireguardSettings';
-import withAppContext, { IAppContext } from '../context';
-import { createWireguardRelayUpdater } from '../lib/constraint-updater';
-import { IHistoryProps, withHistory } from '../lib/history';
-import { RelaySettingsRedux } from '../redux/settings/reducers';
-import { IReduxState, ReduxDispatch } from '../redux/store';
-
-const mapStateToProps = (state: IReduxState, props: IAppContext) => {
- const protocolAndPort = mapRelaySettingsToProtocolAndPort(state.settings.relaySettings);
-
- let wireguardMultihop = false;
- if ('normal' in state.settings.relaySettings) {
- wireguardMultihop = state.settings.relaySettings.normal.wireguard.useMultihop;
- }
-
- return {
- wireguardMtu: state.settings.wireguard.mtu,
- wireguardMultihop,
- ...protocolAndPort,
-
- setWireguardPort: async (port?: number) => {
- const relayUpdate = createWireguardRelayUpdater(state.settings.relaySettings)
- .tunnel.wireguard((wireguard) => {
- if (port) {
- wireguard.port.exact(port);
- } else {
- wireguard.port.any();
- }
- })
- .build();
- try {
- await props.app.updateRelaySettings(relayUpdate);
- } catch (e) {
- const error = e as Error;
- log.error('Failed to update relay settings', error.message);
- }
- },
-
- setWireguardIpVersion: async (ipVersion?: IpVersion) => {
- const relayUpdate = createWireguardRelayUpdater(state.settings.relaySettings)
- .tunnel.wireguard((wireguard) => {
- if (ipVersion) {
- wireguard.ipVersion.exact(ipVersion);
- } else {
- wireguard.ipVersion.any();
- }
- })
- .build();
- try {
- await props.app.updateRelaySettings(relayUpdate);
- } catch (e) {
- const error = e as Error;
- log.error('Failed to update relay settings', error.message);
- }
- },
-
- setWireguardMultihop: async (enabled: boolean) => {
- const relayUpdate = createWireguardRelayUpdater(state.settings.relaySettings)
- .tunnel.wireguard((wireguard) => wireguard.useMultihop(enabled))
- .build();
- try {
- await props.app.updateRelaySettings(relayUpdate);
- } catch (e) {
- const error = e as Error;
- log.error('Failed to update WireGuard multihop settings', error.message);
- }
- },
- };
-};
-
-const mapRelaySettingsToProtocolAndPort = (relaySettings: RelaySettingsRedux) => {
- if ('normal' in relaySettings) {
- const port = relaySettings.normal.wireguard.port;
- const ipVersion = relaySettings.normal.wireguard.ipVersion;
- return {
- wireguard: {
- port: port === 'any' ? undefined : port,
- ipVersion: ipVersion === 'any' ? undefined : ipVersion,
- },
- };
- // since the GUI doesn't display custom settings, just display the default ones.
- // If the user sets any settings, then those will be applied.
- } else if ('customTunnelEndpoint' in relaySettings) {
- return {
- wireguard: { port: undefined },
- };
- } else {
- throw new Error('Unknown type of relay settings.');
- }
-};
-
-const mapDispatchToProps = (_dispatch: ReduxDispatch, props: IHistoryProps & IAppContext) => {
- return {
- onClose: () => {
- props.history.pop();
- },
-
- setWireguardMtu: async (mtu?: number) => {
- try {
- await props.app.setWireguardMtu(mtu);
- } catch (e) {
- const error = e as Error;
- log.error('Failed to update mtu value', error.message);
- }
- },
- };
-};
-
-export default withAppContext(
- withHistory(connect(mapStateToProps, mapDispatchToProps)(WireguardSettings)),
-);
diff --git a/gui/src/renderer/lib/utilityHooks.ts b/gui/src/renderer/lib/utilityHooks.ts
index ca99a76f94..59686f1d6d 100644
--- a/gui/src/renderer/lib/utilityHooks.ts
+++ b/gui/src/renderer/lib/utilityHooks.ts
@@ -44,7 +44,7 @@ export function useAsyncEffect(
}, dependencies);
}
-export function useBoolean(initialValue: boolean) {
+export function useBoolean(initialValue = false) {
const [value, setValue] = useState(initialValue);
const setTrue = useCallback(() => setValue(true), []);