summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-08-18 11:00:22 +0200
committerOskar Nyberg <oskar@mullvad.net>2021-08-19 11:10:07 +0200
commit7f1a1331f87a5cd392cfce1193c229cb05f7945a (patch)
treef0e6f44cdc343020efd543231794606fd2c89298
parent10f11292e778c3700ac301b08a02ad9e29957166 (diff)
downloadmullvadvpn-7f1a1331f87a5cd392cfce1193c229cb05f7945a.tar.xz
mullvadvpn-7f1a1331f87a5cd392cfce1193c229cb05f7945a.zip
Move parts of advanced settings into openvpn and wireguard settings
-rw-r--r--gui/src/renderer/components/AdvancedSettings.tsx357
-rw-r--r--gui/src/renderer/components/AppRouter.tsx8
-rw-r--r--gui/src/renderer/components/OpenVPNSettings.tsx251
-rw-r--r--gui/src/renderer/components/WireguardKeys.tsx2
-rw-r--r--gui/src/renderer/components/WireguardSettings.tsx195
-rw-r--r--gui/src/renderer/containers/AdvancedSettingsPage.tsx103
-rw-r--r--gui/src/renderer/containers/OpenVPNSettingsPage.tsx111
-rw-r--r--gui/src/renderer/containers/WireguardSettingsPage.tsx73
-rw-r--r--gui/src/renderer/lib/routes.ts4
-rw-r--r--gui/src/shared/localization-contexts.ts5
10 files changed, 689 insertions, 420 deletions
diff --git a/gui/src/renderer/components/AdvancedSettings.tsx b/gui/src/renderer/components/AdvancedSettings.tsx
index 338a4d5b81..df2c824358 100644
--- a/gui/src/renderer/components/AdvancedSettings.tsx
+++ b/gui/src/renderer/components/AdvancedSettings.tsx
@@ -1,23 +1,16 @@
import * as React from 'react';
import { sprintf } from 'sprintf-js';
import { colors } from '../../config.json';
-import {
- BridgeState,
- IDnsOptions,
- RelayProtocol,
- TunnelProtocol,
-} from '../../shared/daemon-rpc-types';
+import { IDnsOptions, TunnelProtocol } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
import { IpAddress } from '../lib/ip';
import { WgKeyState } from '../redux/settings/reducers';
import {
StyledButtonCellGroup,
StyledContainer,
- StyledInputFrame,
StyledNavigationScrollbars,
StyledNoWireguardKeyError,
StyledNoWireguardKeyErrorContainer,
- StyledSelectorContainer,
StyledSelectorForFooter,
StyledTunnelProtocolContainer,
StyledCustomDnsSwitchContainer,
@@ -39,52 +32,25 @@ import {
NavigationItems,
TitleBarItem,
} from './NavigationBar';
-import Selector, { ISelectorItem } from './cell/Selector';
+import { ISelectorItem } from './cell/Selector';
import SettingsHeader, { HeaderTitle } from './SettingsHeader';
import Accordion from './Accordion';
import { formatMarkdown } from '../markdown-formatter';
-const MIN_MSSFIX_VALUE = 1000;
-const MAX_MSSFIX_VALUE = 1450;
-const MIN_WIREGUARD_MTU_VALUE = 1280;
-const MAX_WIREGUARD_MTU_VALUE = 1420;
-const UDP_PORTS = [1194, 1195, 1196, 1197, 1300, 1301, 1302];
-const TCP_PORTS = [80, 443];
-const WIREUGARD_UDP_PORTS = [51820, 53];
-
-type OptionalPort = number | undefined;
-
-type OptionalRelayProtocol = RelayProtocol | undefined;
type OptionalTunnelProtocol = TunnelProtocol | undefined;
-function mapPortToSelectorItem(value: number): ISelectorItem<number> {
- return { label: value.toString(), value };
-}
-
interface IProps {
enableIpv6: boolean;
blockWhenDisconnected: boolean;
tunnelProtocol?: TunnelProtocol;
- openvpn: {
- protocol?: RelayProtocol;
- port?: number;
- };
wireguardKeyState: WgKeyState;
- wireguard: { port?: number };
- mssfix?: number;
- wireguardMtu?: number;
- bridgeState: BridgeState;
dns: IDnsOptions;
- setBridgeState: (value: BridgeState) => void;
setEnableIpv6: (value: boolean) => void;
setBlockWhenDisconnected: (value: boolean) => void;
setTunnelProtocol: (value: OptionalTunnelProtocol) => void;
- setOpenVpnMssfix: (value: number | undefined) => void;
- setWireguardMtu: (value: number | undefined) => void;
- setOpenVpnRelayProtocolAndPort: (protocol?: RelayProtocol, port?: number) => void;
- setWireguardRelayPort: (port?: number) => void;
setDnsOptions: (dns: IDnsOptions) => Promise<void>;
- onViewWireguardKeys: () => void;
+ onViewWireguardSettings: () => void;
+ onViewOpenVpnSettings: () => void;
onViewSplitTunneling: () => void;
onClose: () => void;
}
@@ -108,59 +74,6 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
private customDnsAddButtonRef = React.createRef<HTMLButtonElement>();
private customDnsInputContainerRef = React.createRef<HTMLDivElement>();
- private portItems: { [key in RelayProtocol]: Array<ISelectorItem<OptionalPort>> };
- private protocolItems: Array<ISelectorItem<OptionalRelayProtocol>>;
- private bridgeStateItems: Array<ISelectorItem<BridgeState>>;
- private wireguardPortItems: Array<ISelectorItem<OptionalPort>>;
-
- constructor(props: IProps) {
- super(props);
-
- const automaticPort: ISelectorItem<OptionalPort> = {
- label: messages.pgettext('advanced-settings-view', 'Automatic'),
- value: undefined,
- };
-
- this.portItems = {
- udp: [automaticPort].concat(UDP_PORTS.map(mapPortToSelectorItem)),
- tcp: [automaticPort].concat(TCP_PORTS.map(mapPortToSelectorItem)),
- };
-
- this.wireguardPortItems = [automaticPort].concat(
- WIREUGARD_UDP_PORTS.map(mapPortToSelectorItem),
- );
-
- this.protocolItems = [
- {
- label: messages.pgettext('advanced-settings-view', 'Automatic'),
- value: undefined,
- },
- {
- label: messages.pgettext('advanced-settings-view', 'TCP'),
- value: 'tcp',
- },
- {
- label: messages.pgettext('advanced-settings-view', 'UDP'),
- value: 'udp',
- },
- ];
-
- this.bridgeStateItems = [
- {
- label: messages.pgettext('advanced-settings-view', 'Automatic'),
- value: 'auto',
- },
- {
- label: messages.pgettext('advanced-settings-view', 'On'),
- value: 'on',
- },
- {
- label: messages.pgettext('advanced-settings-view', 'Off'),
- value: 'off',
- },
- ];
- }
-
public render() {
const hasWireguardKey = this.props.wireguardKeyState.type === 'key-set';
@@ -245,6 +158,18 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
</Cell.Footer>
</AriaInputGroup>
+ {(window.env.platform === 'linux' || window.env.platform === 'win32') && (
+ <StyledButtonCellGroup>
+ <Cell.CellButton onClick={this.props.onViewSplitTunneling}>
+ <Cell.Label>
+ {window.env.platform === 'win32' && <StyledBetaLabel />}
+ {messages.pgettext('advanced-settings-view', 'Split tunneling')}
+ </Cell.Label>
+ <Cell.Icon height={12} width={7} source="icon-chevron" />
+ </Cell.CellButton>
+ </StyledButtonCellGroup>
+ )}
+
<AriaInputGroup>
<StyledTunnelProtocolContainer>
<StyledSelectorForFooter
@@ -268,189 +193,25 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
</StyledTunnelProtocolContainer>
</AriaInputGroup>
- {this.props.tunnelProtocol !== 'wireguard' ? (
- <AriaInputGroup>
- <StyledSelectorContainer>
- <Selector
- title={messages.pgettext(
- 'advanced-settings-view',
- 'OpenVPN transport protocol',
- )}
- values={this.protocolItems}
- value={this.props.openvpn.protocol}
- onSelect={this.onSelectOpenvpnProtocol}
- />
-
- {this.props.openvpn.protocol ? (
- <Selector
- title={sprintf(
- // TRANSLATORS: The title for the port selector section.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(portType)s - a selected protocol (either TCP or UDP)
- messages.pgettext(
- 'advanced-settings-view',
- 'OpenVPN %(portType)s port',
- ),
- {
- portType: this.props.openvpn.protocol.toUpperCase(),
- },
- )}
- values={this.portItems[this.props.openvpn.protocol]}
- value={this.props.openvpn.port}
- onSelect={this.onSelectOpenVpnPort}
- />
- ) : undefined}
- </StyledSelectorContainer>
- </AriaInputGroup>
- ) : undefined}
-
- {this.props.tunnelProtocol === 'wireguard' ? (
- <AriaInputGroup>
- <StyledSelectorContainer>
- <StyledSelectorForFooter
- // TRANSLATORS: The title for the shadowsocks bridge selector section.
- title={messages.pgettext('advanced-settings-view', 'WireGuard port')}
- values={this.wireguardPortItems}
- value={this.props.wireguard.port}
- onSelect={this.onSelectWireguardPort}
- />
- </StyledSelectorContainer>
- <Cell.Footer>
- <AriaDescription>
- <Cell.FooterText>
- {
- // TRANSLATORS: The hint displayed below the WireGuard port selector.
- messages.pgettext(
- 'advanced-settings-view',
- 'The automatic setting will randomly choose from a wide range of ports.',
- )
- }
- </Cell.FooterText>
- </AriaDescription>
- </Cell.Footer>
- </AriaInputGroup>
- ) : undefined}
-
- <AriaInputGroup>
- <Selector
- title={
- // TRANSLATORS: The title for the shadowsocks bridge selector section.
- messages.pgettext('advanced-settings-view', 'Bridge mode')
- }
- values={this.bridgeStateItems}
- value={this.props.bridgeState}
- onSelect={this.onSelectBridgeState}
- />
- </AriaInputGroup>
-
- <AriaInputGroup>
- <Cell.Container>
- <AriaLabel>
- <Cell.InputLabel>
- {messages.pgettext('advanced-settings-view', 'OpenVPN Mssfix')}
- </Cell.InputLabel>
- </AriaLabel>
- <StyledInputFrame>
- <AriaInput>
- <Cell.AutoSizingTextInput
- value={this.props.mssfix ? this.props.mssfix.toString() : ''}
- inputMode={'numeric'}
- maxLength={4}
- placeholder={messages.pgettext('advanced-settings-view', 'Default')}
- onSubmitValue={this.onMssfixSubmit}
- validateValue={AdvancedSettings.mssfixIsValid}
- submitOnBlur={true}
- modifyValue={AdvancedSettings.removeNonNumericCharacters}
- />
- </AriaInput>
- </StyledInputFrame>
- </Cell.Container>
- <Cell.Footer>
- <AriaDescription>
- <Cell.FooterText>
- {sprintf(
- // TRANSLATORS: The hint displayed below the Mssfix input field.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(max)d - the maximum possible mssfix value
- // TRANSLATORS: %(min)d - the minimum possible mssfix value
- messages.pgettext(
- 'advanced-settings-view',
- 'Set OpenVPN MSS value. Valid range: %(min)d - %(max)d.',
- ),
- {
- min: MIN_MSSFIX_VALUE,
- max: MAX_MSSFIX_VALUE,
- },
- )}
- </Cell.FooterText>
- </AriaDescription>
- </Cell.Footer>
- </AriaInputGroup>
-
- <AriaInputGroup>
- <Cell.Container>
- <AriaLabel>
- <Cell.InputLabel>
- {messages.pgettext('advanced-settings-view', 'WireGuard MTU')}
- </Cell.InputLabel>
- </AriaLabel>
- <StyledInputFrame>
- <AriaInput>
- <Cell.AutoSizingTextInput
- value={this.props.wireguardMtu ? this.props.wireguardMtu.toString() : ''}
- inputMode={'numeric'}
- maxLength={4}
- placeholder={messages.pgettext('advanced-settings-view', 'Default')}
- onSubmitValue={this.onWireguardMtuSubmit}
- validateValue={AdvancedSettings.wireguarMtuIsValid}
- submitOnBlur={true}
- modifyValue={AdvancedSettings.removeNonNumericCharacters}
- />
- </AriaInput>
- </StyledInputFrame>
- </Cell.Container>
- <Cell.Footer>
- <AriaDescription>
- <Cell.FooterText>
- {sprintf(
- // TRANSLATORS: The hint displayed below the WireGuard MTU input field.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(max)d - the maximum possible wireguard mtu value
- // TRANSLATORS: %(min)d - the minimum possible wireguard mtu value
- messages.pgettext(
- 'advanced-settings-view',
- 'Set WireGuard MTU value. Valid range: %(min)d - %(max)d.',
- ),
- {
- min: MIN_WIREGUARD_MTU_VALUE,
- max: MAX_WIREGUARD_MTU_VALUE,
- },
- )}
- </Cell.FooterText>
- </AriaDescription>
- </Cell.Footer>
- </AriaInputGroup>
-
<StyledButtonCellGroup>
- <Cell.CellButton onClick={this.props.onViewWireguardKeys}>
+ <Cell.CellButton
+ onClick={this.props.onViewWireguardSettings}
+ disabled={this.props.tunnelProtocol === 'openvpn'}>
<Cell.Label>
- {messages.pgettext('advanced-settings-view', 'WireGuard key')}
+ {messages.pgettext('advanced-settings-view', 'WireGuard settings')}
</Cell.Label>
<Cell.Icon height={12} width={7} source="icon-chevron" />
</Cell.CellButton>
- </StyledButtonCellGroup>
- {(window.env.platform === 'linux' || window.env.platform === 'win32') && (
- <StyledButtonCellGroup>
- <Cell.CellButton onClick={this.props.onViewSplitTunneling}>
- <Cell.Label>
- {window.env.platform === 'win32' && <StyledBetaLabel />}
- {messages.pgettext('advanced-settings-view', 'Split tunneling')}
- </Cell.Label>
- <Cell.Icon height={12} width={7} source="icon-chevron" />
- </Cell.CellButton>
- </StyledButtonCellGroup>
- )}
+ <Cell.CellButton
+ onClick={this.props.onViewOpenVpnSettings}
+ disabled={this.props.tunnelProtocol === 'wireguard'}>
+ <Cell.Label>
+ {messages.pgettext('advanced-settings-view', 'OpenVPN settings')}
+ </Cell.Label>
+ <Cell.Icon height={12} width={7} source="icon-chevron" />
+ </Cell.CellButton>
+ </StyledButtonCellGroup>
<StyledCustomDnsSwitchContainer disabled={!this.customDnsAvailable()}>
<AriaInputGroup>
@@ -644,19 +405,19 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
value: undefined,
},
{
- label: messages.pgettext('advanced-settings-view', 'OpenVPN'),
- value: 'openvpn',
- },
- {
label: hasWireguardKey
? messages.pgettext('advanced-settings-view', 'WireGuard')
: sprintf('%(label)s (%(error)s)', {
label: messages.pgettext('advanced-settings-view', 'WireGuard'),
- error: messages.pgettext('advanced-settings-view-wireguard', 'missing key'),
+ error: messages.pgettext('advanced-settings-view', 'missing key'),
}),
value: 'wireguard',
disabled: !hasWireguardKey,
},
+ {
+ label: messages.pgettext('advanced-settings-view', 'OpenVPN'),
+ value: 'openvpn',
+ },
];
};
@@ -731,56 +492,6 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
private onSelectTunnelProtocol = (protocol?: TunnelProtocol) => {
this.props.setTunnelProtocol(protocol);
};
-
- private onSelectOpenvpnProtocol = (protocol?: RelayProtocol) => {
- this.props.setOpenVpnRelayProtocolAndPort(protocol);
- };
-
- private onSelectOpenVpnPort = (port?: number) => {
- this.props.setOpenVpnRelayProtocolAndPort(this.props.openvpn.protocol, port);
- };
-
- private onSelectWireguardPort = (port?: number) => {
- this.props.setWireguardRelayPort(port);
- };
-
- private onSelectBridgeState = (bridgeState: BridgeState) => {
- this.props.setBridgeState(bridgeState);
- };
-
- private onMssfixSubmit = (value: string) => {
- const parsedValue = value === '' ? undefined : parseInt(value, 10);
- if (AdvancedSettings.mssfixIsValid(value)) {
- this.props.setOpenVpnMssfix(parsedValue);
- }
- };
-
- private static removeNonNumericCharacters(value: string) {
- return value.replace(/[^0-9]/g, '');
- }
-
- private static mssfixIsValid(mssfix: string): boolean {
- const parsedMssFix = mssfix ? parseInt(mssfix) : undefined;
- return (
- parsedMssFix === undefined ||
- (parsedMssFix >= MIN_MSSFIX_VALUE && parsedMssFix <= MAX_MSSFIX_VALUE)
- );
- }
-
- private onWireguardMtuSubmit = (value: string) => {
- const parsedValue = value === '' ? undefined : parseInt(value, 10);
- if (AdvancedSettings.wireguarMtuIsValid(value)) {
- this.props.setWireguardMtu(parsedValue);
- }
- };
-
- 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)
- );
- }
}
function CustomDnsDisabledMessage() {
diff --git a/gui/src/renderer/components/AppRouter.tsx b/gui/src/renderer/components/AppRouter.tsx
index 9f049fc791..9921109d23 100644
--- a/gui/src/renderer/components/AppRouter.tsx
+++ b/gui/src/renderer/components/AppRouter.tsx
@@ -10,6 +10,7 @@ import TransitionContainer, { TransitionView } from './TransitionContainer';
import AccountPage from '../containers/AccountPage';
import AdvancedSettingsPage from '../containers/AdvancedSettingsPage';
import LoginPage from '../containers/LoginPage';
+import OpenVPNSettingsPage from '../containers/OpenVPNSettingsPage';
import PlatformWindowContainer from '../containers/PlatformWindowContainer';
import PreferencesPage from '../containers/PreferencesPage';
import SelectLanguagePage from '../containers/SelectLanguagePage';
@@ -17,6 +18,7 @@ import SelectLocationPage from '../containers/SelectLocationPage';
import SettingsPage from '../containers/SettingsPage';
import SupportPage from '../containers/SupportPage';
import WireguardKeysPage from '../containers/WireguardKeysPage';
+import WireguardSettingsPage from '../containers/WireguardSettingsPage';
import { IHistoryProps, ITransitionSpecification, transitions, withHistory } from '../lib/history';
import {
SetupFinished,
@@ -91,7 +93,13 @@ class AppRouter extends React.Component<IHistoryProps, IAppRoutesState> {
<Route exact path={RoutePath.accountSettings} component={AccountPage} />
<Route exact path={RoutePath.preferences} component={PreferencesPage} />
<Route exact path={RoutePath.advancedSettings} component={AdvancedSettingsPage} />
+ <Route
+ exact
+ path={RoutePath.wireguardSettings}
+ component={WireguardSettingsPage}
+ />
<Route exact path={RoutePath.wireguardKeys} component={WireguardKeysPage} />
+ <Route exact path={RoutePath.openVpnSettings} component={OpenVPNSettingsPage} />
<Route exact path={RoutePath.splitTunneling} component={SplitTunnelingSettings} />
<Route exact path={RoutePath.support} component={SupportPage} />
<Route exact path={RoutePath.selectLocation} component={SelectLocationPage} />
diff --git a/gui/src/renderer/components/OpenVPNSettings.tsx b/gui/src/renderer/components/OpenVPNSettings.tsx
new file mode 100644
index 0000000000..d3ce2ff507
--- /dev/null
+++ b/gui/src/renderer/components/OpenVPNSettings.tsx
@@ -0,0 +1,251 @@
+import * as React from 'react';
+import { sprintf } from 'sprintf-js';
+import { BridgeState, RelayProtocol } from '../../shared/daemon-rpc-types';
+import { messages } from '../../shared/gettext';
+import {
+ StyledContainer,
+ StyledInputFrame,
+ StyledNavigationScrollbars,
+ StyledSelectorContainer,
+} from './AdvancedSettingsStyles';
+import { AriaDescription, AriaInput, AriaInputGroup, AriaLabel } from './AriaGroup';
+import * as Cell from './cell';
+import { Layout } from './Layout';
+import { ModalContainer } from './Modal';
+import {
+ BackBarItem,
+ NavigationBar,
+ NavigationContainer,
+ NavigationItems,
+ TitleBarItem,
+} from './NavigationBar';
+import Selector, { ISelectorItem } from './cell/Selector';
+import SettingsHeader, { HeaderTitle } from './SettingsHeader';
+
+const MIN_MSSFIX_VALUE = 1000;
+const MAX_MSSFIX_VALUE = 1450;
+const UDP_PORTS = [1194, 1195, 1196, 1197, 1300, 1301, 1302];
+const TCP_PORTS = [80, 443];
+
+type OptionalPort = number | undefined;
+
+type OptionalRelayProtocol = RelayProtocol | undefined;
+
+function mapPortToSelectorItem(value: number): ISelectorItem<number> {
+ return { label: value.toString(), value };
+}
+
+interface IProps {
+ openvpn: {
+ protocol?: RelayProtocol;
+ port?: number;
+ };
+ mssfix?: number;
+ bridgeState: BridgeState;
+ setOpenVpnMssfix: (value: number | undefined) => void;
+ setOpenVpnRelayProtocolAndPort: (protocol?: RelayProtocol, port?: number) => void;
+ setBridgeState: (value: BridgeState) => void;
+ onClose: () => void;
+}
+
+export default class OpenVpnSettings extends React.Component<IProps> {
+ private portItems: { [key in RelayProtocol]: Array<ISelectorItem<OptionalPort>> };
+ private protocolItems: Array<ISelectorItem<OptionalRelayProtocol>>;
+ private bridgeStateItems: Array<ISelectorItem<BridgeState>>;
+
+ constructor(props: IProps) {
+ super(props);
+
+ const automaticPort: ISelectorItem<OptionalPort> = {
+ label: messages.gettext('Automatic'),
+ value: undefined,
+ };
+
+ this.portItems = {
+ udp: [automaticPort].concat(UDP_PORTS.map(mapPortToSelectorItem)),
+ tcp: [automaticPort].concat(TCP_PORTS.map(mapPortToSelectorItem)),
+ };
+
+ this.protocolItems = [
+ {
+ label: messages.gettext('Automatic'),
+ value: undefined,
+ },
+ {
+ label: messages.gettext('TCP'),
+ value: 'tcp',
+ },
+ {
+ label: messages.gettext('UDP'),
+ value: 'udp',
+ },
+ ];
+
+ this.bridgeStateItems = [
+ {
+ label: messages.gettext('Automatic'),
+ value: 'auto',
+ },
+ {
+ label: messages.gettext('On'),
+ value: 'on',
+ },
+ {
+ label: messages.gettext('Off'),
+ value: 'off',
+ },
+ ];
+ }
+
+ public render() {
+ return (
+ <ModalContainer>
+ <Layout>
+ <StyledContainer>
+ <NavigationContainer>
+ <NavigationBar>
+ <NavigationItems>
+ <BackBarItem action={this.props.onClose}>
+ {
+ // TRANSLATORS: Back button in navigation bar
+ messages.pgettext('navigation-bar', 'Advanced')
+ }
+ </BackBarItem>
+ <TitleBarItem>
+ {
+ // TRANSLATORS: Title label in navigation bar
+ messages.pgettext('openvpn-settings-nav', 'OpenVPN settings')
+ }
+ </TitleBarItem>
+ </NavigationItems>
+ </NavigationBar>
+
+ <StyledNavigationScrollbars>
+ <SettingsHeader>
+ <HeaderTitle>
+ {messages.pgettext('openvpn-settings-view', 'OpenVPN settings')}
+ </HeaderTitle>
+ </SettingsHeader>
+
+ <AriaInputGroup>
+ <StyledSelectorContainer>
+ <Selector
+ title={messages.pgettext('openvpn-settings-view', 'Transport protocol')}
+ values={this.protocolItems}
+ value={this.props.openvpn.protocol}
+ onSelect={this.onSelectOpenvpnProtocol}
+ />
+
+ {this.props.openvpn.protocol ? (
+ <Selector
+ title={sprintf(
+ // TRANSLATORS: The title for the port selector section.
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(portType)s - a selected protocol (either TCP or UDP)
+ messages.pgettext('openvpn-settings-view', '%(portType)s port'),
+ {
+ portType: this.props.openvpn.protocol.toUpperCase(),
+ },
+ )}
+ values={this.portItems[this.props.openvpn.protocol]}
+ value={this.props.openvpn.port}
+ onSelect={this.onSelectOpenVpnPort}
+ />
+ ) : undefined}
+ </StyledSelectorContainer>
+ </AriaInputGroup>
+
+ <AriaInputGroup>
+ <Selector
+ title={
+ // TRANSLATORS: The title for the shadowsocks bridge selector section.
+ messages.pgettext('openvpn-settings-view', 'Bridge mode')
+ }
+ values={this.bridgeStateItems}
+ value={this.props.bridgeState}
+ onSelect={this.onSelectBridgeState}
+ />
+ </AriaInputGroup>
+
+ <AriaInputGroup>
+ <Cell.Container>
+ <AriaLabel>
+ <Cell.InputLabel>
+ {messages.pgettext('openvpn-settings-view', 'Mssfix')}
+ </Cell.InputLabel>
+ </AriaLabel>
+ <StyledInputFrame>
+ <AriaInput>
+ <Cell.AutoSizingTextInput
+ value={this.props.mssfix ? this.props.mssfix.toString() : ''}
+ inputMode={'numeric'}
+ maxLength={4}
+ placeholder={messages.gettext('Default')}
+ onSubmitValue={this.onMssfixSubmit}
+ validateValue={OpenVpnSettings.mssfixIsValid}
+ submitOnBlur={true}
+ modifyValue={OpenVpnSettings.removeNonNumericCharacters}
+ />
+ </AriaInput>
+ </StyledInputFrame>
+ </Cell.Container>
+ <Cell.Footer>
+ <AriaDescription>
+ <Cell.FooterText>
+ {sprintf(
+ // TRANSLATORS: The hint displayed below the Mssfix input field.
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(max)d - the maximum possible mssfix value
+ // TRANSLATORS: %(min)d - the minimum possible mssfix value
+ messages.pgettext(
+ 'openvpn-settings-view',
+ 'Set OpenVPN MSS value. Valid range: %(min)d - %(max)d.',
+ ),
+ {
+ min: MIN_MSSFIX_VALUE,
+ max: MAX_MSSFIX_VALUE,
+ },
+ )}
+ </Cell.FooterText>
+ </AriaDescription>
+ </Cell.Footer>
+ </AriaInputGroup>
+ </StyledNavigationScrollbars>
+ </NavigationContainer>
+ </StyledContainer>
+ </Layout>
+ </ModalContainer>
+ );
+ }
+
+ private onSelectOpenvpnProtocol = (protocol?: RelayProtocol) => {
+ this.props.setOpenVpnRelayProtocolAndPort(protocol);
+ };
+
+ private onSelectOpenVpnPort = (port?: number) => {
+ this.props.setOpenVpnRelayProtocolAndPort(this.props.openvpn.protocol, port);
+ };
+
+ private onSelectBridgeState = (bridgeState: BridgeState) => {
+ this.props.setBridgeState(bridgeState);
+ };
+
+ private onMssfixSubmit = (value: string) => {
+ const parsedValue = value === '' ? undefined : parseInt(value, 10);
+ if (OpenVpnSettings.mssfixIsValid(value)) {
+ this.props.setOpenVpnMssfix(parsedValue);
+ }
+ };
+
+ private static removeNonNumericCharacters(value: string) {
+ return value.replace(/[^0-9]/g, '');
+ }
+
+ private static mssfixIsValid(mssfix: string): boolean {
+ const parsedMssFix = mssfix ? parseInt(mssfix) : undefined;
+ return (
+ parsedMssFix === undefined ||
+ (parsedMssFix >= MIN_MSSFIX_VALUE && parsedMssFix <= MAX_MSSFIX_VALUE)
+ );
+ }
+}
diff --git a/gui/src/renderer/components/WireguardKeys.tsx b/gui/src/renderer/components/WireguardKeys.tsx
index f6e143e6a3..e76820b006 100644
--- a/gui/src/renderer/components/WireguardKeys.tsx
+++ b/gui/src/renderer/components/WireguardKeys.tsx
@@ -103,7 +103,7 @@ export default class WireguardKeys extends React.Component<IProps, IState> {
<BackBarItem action={this.props.onClose}>
{
// TRANSLATORS: Back button in navigation bar
- messages.pgettext('wireguard-keys-nav', 'Advanced')
+ messages.pgettext('wireguard-keys-nav', 'WireGuard settings')
}
</BackBarItem>
<TitleBarItem>
diff --git a/gui/src/renderer/components/WireguardSettings.tsx b/gui/src/renderer/components/WireguardSettings.tsx
new file mode 100644
index 0000000000..91e55b2c49
--- /dev/null
+++ b/gui/src/renderer/components/WireguardSettings.tsx
@@ -0,0 +1,195 @@
+import * as React from 'react';
+import { sprintf } from 'sprintf-js';
+import { messages } from '../../shared/gettext';
+import {
+ StyledButtonCellGroup,
+ StyledContainer,
+ StyledInputFrame,
+ StyledNavigationScrollbars,
+ StyledSelectorContainer,
+ StyledSelectorForFooter,
+} from './AdvancedSettingsStyles';
+import { AriaDescription, AriaInput, AriaInputGroup, AriaLabel } from './AriaGroup';
+import * as Cell from './cell';
+import { Layout } from './Layout';
+import {
+ BackBarItem,
+ NavigationBar,
+ NavigationContainer,
+ NavigationItems,
+ TitleBarItem,
+} from './NavigationBar';
+import { ISelectorItem } from './cell/Selector';
+import SettingsHeader, { HeaderTitle } from './SettingsHeader';
+
+const MIN_WIREGUARD_MTU_VALUE = 1280;
+const MAX_WIREGUARD_MTU_VALUE = 1420;
+const WIREUGARD_UDP_PORTS = [51820, 53];
+
+type OptionalPort = number | undefined;
+
+function mapPortToSelectorItem(value: number): ISelectorItem<number> {
+ return { label: value.toString(), value };
+}
+
+interface IProps {
+ wireguard: { port?: number };
+ wireguardMtu?: number;
+ setWireguardMtu: (value: number | undefined) => void;
+ setWireguardRelayPort: (port?: number) => void;
+ onViewWireguardKeys: () => void;
+ onClose: () => void;
+}
+
+export default class WireguardSettings extends React.Component<IProps> {
+ private wireguardPortItems: Array<ISelectorItem<OptionalPort>>;
+
+ constructor(props: IProps) {
+ super(props);
+
+ const automaticPort: ISelectorItem<OptionalPort> = {
+ label: messages.gettext('Automatic'),
+ value: undefined,
+ };
+
+ this.wireguardPortItems = [automaticPort].concat(
+ WIREUGARD_UDP_PORTS.map(mapPortToSelectorItem),
+ );
+ }
+
+ public render() {
+ return (
+ <Layout>
+ <StyledContainer>
+ <NavigationContainer>
+ <NavigationBar>
+ <NavigationItems>
+ <BackBarItem action={this.props.onClose}>
+ {
+ // TRANSLATORS: Back button in navigation bar
+ messages.pgettext('navigation-bar', 'Advanced')
+ }
+ </BackBarItem>
+ <TitleBarItem>
+ {
+ // TRANSLATORS: Title label in navigation bar
+ messages.pgettext('wireguard-settings-nav', 'WireGuard settings')
+ }
+ </TitleBarItem>
+ </NavigationItems>
+ </NavigationBar>
+
+ <StyledNavigationScrollbars>
+ <SettingsHeader>
+ <HeaderTitle>
+ {messages.pgettext('wireguard-settings-view', 'WireGuard settings')}
+ </HeaderTitle>
+ </SettingsHeader>
+
+ <AriaInputGroup>
+ <StyledSelectorContainer>
+ <StyledSelectorForFooter
+ // TRANSLATORS: The title for the shadowsocks bridge selector section.
+ title={messages.pgettext('wireguard-settings-view', 'Port')}
+ values={this.wireguardPortItems}
+ value={this.props.wireguard.port}
+ onSelect={this.onSelectWireguardPort}
+ />
+ </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>
+
+ <StyledButtonCellGroup>
+ <Cell.CellButton onClick={this.props.onViewWireguardKeys}>
+ <Cell.Label>
+ {messages.pgettext('wireguard-settings-view', 'WireGuard key')}
+ </Cell.Label>
+ <Cell.Icon height={12} width={7} source="icon-chevron" />
+ </Cell.CellButton>
+ </StyledButtonCellGroup>
+
+ <AriaInputGroup>
+ <Cell.Container>
+ <AriaLabel>
+ <Cell.InputLabel>
+ {messages.pgettext('wireguard-settings-view', 'MTU')}
+ </Cell.InputLabel>
+ </AriaLabel>
+ <StyledInputFrame>
+ <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>
+ </StyledInputFrame>
+ </Cell.Container>
+ <Cell.Footer>
+ <AriaDescription>
+ <Cell.FooterText>
+ {sprintf(
+ // TRANSLATORS: The hint displayed below the WireGuard MTU input field.
+ // TRANSLATORS: Available placeholders:
+ // 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 MTU value. Valid range: %(min)d - %(max)d.',
+ ),
+ {
+ min: MIN_WIREGUARD_MTU_VALUE,
+ max: MAX_WIREGUARD_MTU_VALUE,
+ },
+ )}
+ </Cell.FooterText>
+ </AriaDescription>
+ </Cell.Footer>
+ </AriaInputGroup>
+ </StyledNavigationScrollbars>
+ </NavigationContainer>
+ </StyledContainer>
+ </Layout>
+ );
+ }
+
+ private onSelectWireguardPort = (port?: number) => {
+ this.props.setWireguardRelayPort(port);
+ };
+
+ private static removeNonNumericCharacters(value: string) {
+ return value.replace(/[^0-9]/g, '');
+ }
+
+ private onWireguardMtuSubmit = (value: string) => {
+ const parsedValue = value === '' ? undefined : parseInt(value, 10);
+ if (WireguardSettings.wireguarMtuIsValid(value)) {
+ this.props.setWireguardMtu(parsedValue);
+ }
+ };
+
+ 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)
+ );
+ }
+}
diff --git a/gui/src/renderer/containers/AdvancedSettingsPage.tsx b/gui/src/renderer/containers/AdvancedSettingsPage.tsx
index d16f193ce0..afd6134042 100644
--- a/gui/src/renderer/containers/AdvancedSettingsPage.tsx
+++ b/gui/src/renderer/containers/AdvancedSettingsPage.tsx
@@ -1,10 +1,5 @@
import { connect } from 'react-redux';
-import {
- BridgeState,
- IDnsOptions,
- RelayProtocol,
- TunnelProtocol,
-} from '../../shared/daemon-rpc-types';
+import { IDnsOptions, TunnelProtocol } from '../../shared/daemon-rpc-types';
import log from '../../shared/logging';
import RelaySettingsBuilder from '../../shared/relay-settings-builder';
import AdvancedSettings from '../components/AdvancedSettings';
@@ -16,42 +11,25 @@ import { RelaySettingsRedux } from '../redux/settings/reducers';
import { IReduxState, ReduxDispatch } from '../redux/store';
const mapStateToProps = (state: IReduxState) => {
- const protocolAndPort = mapRelaySettingsToProtocolAndPort(state.settings.relaySettings);
+ const tunnelProtocol = mapRelaySettingsToProtocol(state.settings.relaySettings);
return {
enableIpv6: state.settings.enableIpv6,
blockWhenDisconnected: state.settings.blockWhenDisconnected,
wireguardKeyState: state.settings.wireguardKeyState,
- mssfix: state.settings.openVpn.mssfix,
- wireguardMtu: state.settings.wireguard.mtu,
- bridgeState: state.settings.bridgeState,
dns: state.settings.dns,
- ...protocolAndPort,
+ tunnelProtocol,
};
};
-const mapRelaySettingsToProtocolAndPort = (relaySettings: RelaySettingsRedux) => {
+const mapRelaySettingsToProtocol = (relaySettings: RelaySettingsRedux) => {
if ('normal' in relaySettings) {
- const { tunnelProtocol, openvpn, wireguard } = relaySettings.normal;
- return {
- openvpn: {
- protocol: openvpn.protocol === 'any' ? undefined : openvpn.protocol,
- port: openvpn.port === 'any' ? undefined : openvpn.port,
- },
- wireguard: { port: wireguard.port === 'any' ? undefined : wireguard.port },
- tunnelProtocol: tunnelProtocol === 'any' ? undefined : tunnelProtocol,
- };
+ const { tunnelProtocol } = relaySettings.normal;
+ return tunnelProtocol === 'any' ? undefined : tunnelProtocol;
// 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 {
- openvpn: {
- protocol: undefined,
- port: undefined,
- },
- wireguard: { port: undefined },
- tunnelProtocol: undefined,
- };
+ return undefined;
} else {
throw new Error('Unknown type of relay settings.');
}
@@ -62,46 +40,6 @@ const mapDispatchToProps = (_dispatch: ReduxDispatch, props: IHistoryProps & IAp
onClose: () => {
props.history.pop();
},
- setOpenVpnRelayProtocolAndPort: async (protocol?: RelayProtocol, port?: number) => {
- const relayUpdate = RelaySettingsBuilder.normal()
- .tunnel.openvpn((openvpn) => {
- if (protocol) {
- openvpn.protocol.exact(protocol);
- } else {
- openvpn.protocol.any();
- }
-
- if (port) {
- openvpn.port.exact(port);
- } else {
- openvpn.port.any();
- }
- })
- .build();
-
- try {
- await props.app.updateRelaySettings(relayUpdate);
- } catch (e) {
- log.error('Failed to update relay settings', e.message);
- }
- },
-
- setWireguardRelayPort: async (port?: number) => {
- const relayUpdate = RelaySettingsBuilder.normal()
- .tunnel.wireguard((wireguard) => {
- if (port) {
- wireguard.port.exact(port);
- } else {
- wireguard.port.any();
- }
- })
- .build();
- try {
- await props.app.updateRelaySettings(relayUpdate);
- } catch (e) {
- log.error('Failed to update relay settings', e.message);
- }
- },
setTunnelProtocol: async (tunnelProtocol: TunnelProtocol | undefined) => {
const relayUpdate = RelaySettingsBuilder.normal()
@@ -136,35 +74,12 @@ const mapDispatchToProps = (_dispatch: ReduxDispatch, props: IHistoryProps & IAp
}
},
- setBridgeState: async (bridgeState: BridgeState) => {
- try {
- await props.app.setBridgeState(bridgeState);
- } catch (e) {
- log.error(`Failed to update bridge state: ${e.message}`);
- }
- },
-
- setOpenVpnMssfix: async (mssfix?: number) => {
- try {
- await props.app.setOpenVpnMssfix(mssfix);
- } catch (e) {
- log.error('Failed to update mssfix value', e.message);
- }
- },
-
- setWireguardMtu: async (mtu?: number) => {
- try {
- await props.app.setWireguardMtu(mtu);
- } catch (e) {
- log.error('Failed to update mtu value', e.message);
- }
- },
-
setDnsOptions: (dns: IDnsOptions) => {
return props.app.setDnsOptions(dns);
},
- onViewWireguardKeys: () => props.history.push(RoutePath.wireguardKeys),
+ onViewWireguardSettings: () => props.history.push(RoutePath.wireguardSettings),
+ onViewOpenVpnSettings: () => props.history.push(RoutePath.openVpnSettings),
onViewSplitTunneling: () => props.history.push(RoutePath.splitTunneling),
};
};
diff --git a/gui/src/renderer/containers/OpenVPNSettingsPage.tsx b/gui/src/renderer/containers/OpenVPNSettingsPage.tsx
new file mode 100644
index 0000000000..378dc9bb82
--- /dev/null
+++ b/gui/src/renderer/containers/OpenVPNSettingsPage.tsx
@@ -0,0 +1,111 @@
+import { connect } from 'react-redux';
+import { BridgeState, RelayProtocol } from '../../shared/daemon-rpc-types';
+import log from '../../shared/logging';
+import RelaySettingsBuilder from '../../shared/relay-settings-builder';
+import OpenVPNSettings from '../components/OpenVPNSettings';
+
+import withAppContext, { IAppContext } from '../context';
+import { IHistoryProps, withHistory } from '../lib/history';
+import { RelaySettingsRedux } from '../redux/settings/reducers';
+import { IReduxState, ReduxDispatch } from '../redux/store';
+
+const mapStateToProps = (state: IReduxState) => {
+ const protocolAndPort = mapRelaySettingsToProtocolAndPort(state.settings.relaySettings);
+
+ return {
+ mssfix: state.settings.openVpn.mssfix,
+ bridgeState: state.settings.bridgeState,
+ ...protocolAndPort,
+ };
+};
+
+const mapRelaySettingsToProtocolAndPort = (relaySettings: RelaySettingsRedux) => {
+ if ('normal' in relaySettings) {
+ const { openvpn } = relaySettings.normal;
+ return {
+ openvpn: {
+ protocol: openvpn.protocol === 'any' ? undefined : openvpn.protocol,
+ port: openvpn.port === 'any' ? undefined : openvpn.port,
+ },
+ };
+ // 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 {
+ openvpn: {
+ protocol: undefined,
+ port: undefined,
+ },
+ };
+ } else {
+ throw new Error('Unknown type of relay settings.');
+ }
+};
+
+const mapDispatchToProps = (_dispatch: ReduxDispatch, props: IHistoryProps & IAppContext) => {
+ return {
+ onClose: () => {
+ props.history.pop();
+ },
+ setOpenVpnRelayProtocolAndPort: async (protocol?: RelayProtocol, port?: number) => {
+ const relayUpdate = RelaySettingsBuilder.normal()
+ .tunnel.openvpn((openvpn) => {
+ if (protocol) {
+ openvpn.protocol.exact(protocol);
+ } else {
+ openvpn.protocol.any();
+ }
+
+ if (port) {
+ openvpn.port.exact(port);
+ } else {
+ openvpn.port.any();
+ }
+ })
+ .build();
+
+ try {
+ await props.app.updateRelaySettings(relayUpdate);
+ } catch (e) {
+ log.error('Failed to update relay settings', e.message);
+ }
+ },
+
+ setWireguardRelayPort: async (port?: number) => {
+ const relayUpdate = RelaySettingsBuilder.normal()
+ .tunnel.wireguard((wireguard) => {
+ if (port) {
+ wireguard.port.exact(port);
+ } else {
+ wireguard.port.any();
+ }
+ })
+ .build();
+ try {
+ await props.app.updateRelaySettings(relayUpdate);
+ } catch (e) {
+ log.error('Failed to update relay settings', e.message);
+ }
+ },
+
+ setBridgeState: async (bridgeState: BridgeState) => {
+ try {
+ await props.app.setBridgeState(bridgeState);
+ } catch (e) {
+ log.error(`Failed to update bridge state: ${e.message}`);
+ }
+ },
+
+ setOpenVpnMssfix: async (mssfix?: number) => {
+ try {
+ await props.app.setOpenVpnMssfix(mssfix);
+ } catch (e) {
+ log.error('Failed to update mssfix value', e.message);
+ }
+ },
+ };
+};
+
+export default withAppContext(
+ withHistory(connect(mapStateToProps, mapDispatchToProps)(OpenVPNSettings)),
+);
diff --git a/gui/src/renderer/containers/WireguardSettingsPage.tsx b/gui/src/renderer/containers/WireguardSettingsPage.tsx
new file mode 100644
index 0000000000..e89bcff62a
--- /dev/null
+++ b/gui/src/renderer/containers/WireguardSettingsPage.tsx
@@ -0,0 +1,73 @@
+import { connect } from 'react-redux';
+import log from '../../shared/logging';
+import RelaySettingsBuilder from '../../shared/relay-settings-builder';
+import WireguardSettings from '../components/WireguardSettings';
+
+import withAppContext, { IAppContext } from '../context';
+import { IHistoryProps, withHistory } from '../lib/history';
+import { RoutePath } from '../lib/routes';
+import { RelaySettingsRedux } from '../redux/settings/reducers';
+import { IReduxState, ReduxDispatch } from '../redux/store';
+
+const mapStateToProps = (state: IReduxState) => {
+ const protocolAndPort = mapRelaySettingsToProtocolAndPort(state.settings.relaySettings);
+
+ return {
+ wireguardMtu: state.settings.wireguard.mtu,
+ ...protocolAndPort,
+ };
+};
+
+const mapRelaySettingsToProtocolAndPort = (relaySettings: RelaySettingsRedux) => {
+ if ('normal' in relaySettings) {
+ const port = relaySettings.normal.wireguard.port;
+ return { wireguard: { port: port === 'any' ? undefined : port } };
+ // 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();
+ },
+
+ setWireguardRelayPort: async (port?: number) => {
+ const relayUpdate = RelaySettingsBuilder.normal()
+ .tunnel.wireguard((wireguard) => {
+ if (port) {
+ wireguard.port.exact(port);
+ } else {
+ wireguard.port.any();
+ }
+ })
+ .build();
+ try {
+ await props.app.updateRelaySettings(relayUpdate);
+ } catch (e) {
+ log.error('Failed to update relay settings', e.message);
+ }
+ },
+
+ setWireguardMtu: async (mtu?: number) => {
+ try {
+ await props.app.setWireguardMtu(mtu);
+ } catch (e) {
+ log.error('Failed to update mtu value', e.message);
+ }
+ },
+
+ onViewWireguardKeys: () => props.history.push(RoutePath.wireguardKeys),
+ };
+};
+
+export default withAppContext(
+ withHistory(connect(mapStateToProps, mapDispatchToProps)(WireguardSettings)),
+);
diff --git a/gui/src/renderer/lib/routes.ts b/gui/src/renderer/lib/routes.ts
index 8d8c2ce27b..dee83c2a42 100644
--- a/gui/src/renderer/lib/routes.ts
+++ b/gui/src/renderer/lib/routes.ts
@@ -11,7 +11,9 @@ export enum RoutePath {
accountSettings = '/settings/account',
preferences = '/settings/preferences',
advancedSettings = '/settings/advanced',
- wireguardKeys = '/settings/advanced/wireguard-keys',
+ wireguardSettings = '/settings/advanced/wireguard',
+ wireguardKeys = '/settings/advanced/wireguard/keys',
+ openVpnSettings = '/settings/advanced/openvpn',
splitTunneling = '/settings/advanced/split-tunneling',
support = '/settings/support',
selectLocation = '/select-location',
diff --git a/gui/src/shared/localization-contexts.ts b/gui/src/shared/localization-contexts.ts
index 7e80e68a5b..b39dcc0681 100644
--- a/gui/src/shared/localization-contexts.ts
+++ b/gui/src/shared/localization-contexts.ts
@@ -25,7 +25,10 @@ export type LocalizationContexts =
| 'preferences-nav'
| 'advanced-settings-view'
| 'advanced-settings-nav'
- | 'advanced-settings-view-wireguard'
+ | 'wireguard-settings-view'
+ | 'wireguard-settings-nav'
+ | 'openvpn-settings-view'
+ | 'openvpn-settings-nav'
| 'wireguard-key-view'
| 'wireguard-keys-nav'
| 'split-tunneling-view'