summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-08-19 11:10:18 +0200
committerOskar Nyberg <oskar@mullvad.net>2021-08-19 11:10:18 +0200
commit281488dcbf634fc93bab1991bbcc8f4f97d118ae (patch)
tree9135a58df3b478f9855d22a797784ccdafd896db
parent10f11292e778c3700ac301b08a02ad9e29957166 (diff)
parentc5fdf899a223f820bf971b968f384dfe2e45592f (diff)
downloadmullvadvpn-281488dcbf634fc93bab1991bbcc8f4f97d118ae.tar.xz
mullvadvpn-281488dcbf634fc93bab1991bbcc8f4f97d118ae.zip
Merge branch 'reorganize-advanced-settings'
-rw-r--r--CHANGELOG.md1
-rw-r--r--gui/locales/messages.pot167
-rw-r--r--gui/src/renderer/components/AdvancedSettings.tsx367
-rw-r--r--gui/src/renderer/components/AdvancedSettingsStyles.tsx12
-rw-r--r--gui/src/renderer/components/AppRouter.tsx8
-rw-r--r--gui/src/renderer/components/Layout.tsx4
-rw-r--r--gui/src/renderer/components/OpenVPNSettings.tsx259
-rw-r--r--gui/src/renderer/components/WireguardKeys.tsx2
-rw-r--r--gui/src/renderer/components/WireguardSettings.tsx205
-rw-r--r--gui/src/renderer/components/cell/CellButton.tsx9
-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
15 files changed, 821 insertions, 509 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16c1fd48bd..42aa88794d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,7 @@ Line wrap the file at 100 chars. Th
beta.
- Upgrade OpenVPN from 2.5.1 to 2.5.3.
- Update Electron from 11.2.3 to 11.4.9.
+- Move OpenVPN and WireGuard settings in the advanced settings view into separate settings views.
#### Windows
- Upgrade Wintun from 0.10.4 to 0.13.
diff --git a/gui/locales/messages.pot b/gui/locales/messages.pot
index 09e121d68b..64733884ef 100644
--- a/gui/locales/messages.pot
+++ b/gui/locales/messages.pot
@@ -63,6 +63,9 @@ msgstr[1] ""
msgid "Apply"
msgstr ""
+msgid "Automatic"
+msgstr ""
+
msgid "Back"
msgstr ""
@@ -96,6 +99,9 @@ msgstr ""
msgid "CREATING SECURE CONNECTION"
msgstr ""
+msgid "Default"
+msgstr ""
+
msgid "Disconnect"
msgstr ""
@@ -126,6 +132,12 @@ msgstr ""
msgid "Next"
msgstr ""
+msgid "Off"
+msgstr ""
+
+msgid "On"
+msgstr ""
+
msgid "Open URL"
msgstr ""
@@ -141,6 +153,12 @@ msgstr ""
msgid "System default"
msgstr ""
+msgid "TCP"
+msgstr ""
+
+msgid "UDP"
+msgstr ""
+
msgid "UNSECURE CONNECTION"
msgstr ""
@@ -231,15 +249,6 @@ msgctxt "advanced-settings-view"
msgid "Automatic"
msgstr ""
-#. The title for the shadowsocks bridge selector section.
-msgctxt "advanced-settings-view"
-msgid "Bridge mode"
-msgstr ""
-
-msgctxt "advanced-settings-view"
-msgid "Default"
-msgstr ""
-
msgctxt "advanced-settings-view"
msgid "Enable anyway"
msgstr ""
@@ -265,46 +274,15 @@ msgid "If you disconnect or quit the app, this setting will block your internet.
msgstr ""
msgctxt "advanced-settings-view"
-msgid "Off"
-msgstr ""
-
-msgctxt "advanced-settings-view"
-msgid "On"
+msgid "missing key"
msgstr ""
msgctxt "advanced-settings-view"
msgid "OpenVPN"
msgstr ""
-#. The title for the port selector section.
-#. Available placeholders:
-#. %(portType)s - a selected protocol (either TCP or UDP)
-msgctxt "advanced-settings-view"
-msgid "OpenVPN %(portType)s port"
-msgstr ""
-
-msgctxt "advanced-settings-view"
-msgid "OpenVPN Mssfix"
-msgstr ""
-
-msgctxt "advanced-settings-view"
-msgid "OpenVPN transport protocol"
-msgstr ""
-
-#. The hint displayed below the Mssfix input field.
-#. Available placeholders:
-#. %(max)d - the maximum possible mssfix value
-#. %(min)d - the minimum possible mssfix value
-msgctxt "advanced-settings-view"
-msgid "Set OpenVPN MSS value. Valid range: %(min)d - %(max)d."
-msgstr ""
-
-#. The hint displayed below the WireGuard MTU input field.
-#. Available placeholders:
-#. %(max)d - the maximum possible wireguard mtu value
-#. %(min)d - the minimum possible wireguard mtu value
msgctxt "advanced-settings-view"
-msgid "Set WireGuard MTU value. Valid range: %(min)d - %(max)d."
+msgid "OpenVPN settings"
msgstr ""
msgctxt "advanced-settings-view"
@@ -312,18 +290,9 @@ msgid "Split tunneling"
msgstr ""
msgctxt "advanced-settings-view"
-msgid "TCP"
-msgstr ""
-
-msgctxt "advanced-settings-view"
msgid "The app’s built-in kill switch is always on. This setting will additionally block the internet if clicking Disconnect or Quit."
msgstr ""
-#. The hint displayed below the WireGuard port selector.
-msgctxt "advanced-settings-view"
-msgid "The automatic setting will randomly choose from a wide range of ports."
-msgstr ""
-
msgctxt "advanced-settings-view"
msgid "The DNS server you want to add is public and will only work with WireGuard. To ensure that it always works, set the \"Tunnel protocol\" (in Advanced settings) to WireGuard."
msgstr ""
@@ -337,10 +306,6 @@ msgid "Tunnel protocol"
msgstr ""
msgctxt "advanced-settings-view"
-msgid "UDP"
-msgstr ""
-
-msgctxt "advanced-settings-view"
msgid "Use custom DNS server"
msgstr ""
@@ -349,19 +314,7 @@ msgid "WireGuard"
msgstr ""
msgctxt "advanced-settings-view"
-msgid "WireGuard key"
-msgstr ""
-
-msgctxt "advanced-settings-view"
-msgid "WireGuard MTU"
-msgstr ""
-
-msgctxt "advanced-settings-view"
-msgid "WireGuard port"
-msgstr ""
-
-msgctxt "advanced-settings-view-wireguard"
-msgid "missing key"
+msgid "WireGuard settings"
msgstr ""
msgctxt "auth-failure"
@@ -785,6 +738,43 @@ msgid "Your selected server and tunnel protocol don't match. Please adjust your
msgstr ""
#. Title label in navigation bar
+msgctxt "openvpn-settings-nav"
+msgid "OpenVPN settings"
+msgstr ""
+
+#. The title for the port selector section.
+#. Available placeholders:
+#. %(portType)s - a selected protocol (either TCP or UDP)
+msgctxt "openvpn-settings-view"
+msgid "%(portType)s port"
+msgstr ""
+
+#. The title for the shadowsocks bridge selector section.
+msgctxt "openvpn-settings-view"
+msgid "Bridge mode"
+msgstr ""
+
+msgctxt "openvpn-settings-view"
+msgid "Mssfix"
+msgstr ""
+
+msgctxt "openvpn-settings-view"
+msgid "OpenVPN settings"
+msgstr ""
+
+#. The hint displayed below the Mssfix input field.
+#. Available placeholders:
+#. %(max)d - the maximum possible mssfix value
+#. %(min)d - the minimum possible mssfix value
+msgctxt "openvpn-settings-view"
+msgid "Set OpenVPN MSS value. Valid range: %(min)d - %(max)d."
+msgstr ""
+
+msgctxt "openvpn-settings-view"
+msgid "Transport protocol"
+msgstr ""
+
+#. Title label in navigation bar
msgctxt "preferences-nav"
msgid "Preferences"
msgstr ""
@@ -1236,16 +1226,50 @@ msgctxt "wireguard-key-view"
msgid "Verify key"
msgstr ""
+#. Title label in navigation bar
+msgctxt "wireguard-keys-nav"
+msgid "WireGuard key"
+msgstr ""
+
#. Back button in navigation bar
msgctxt "wireguard-keys-nav"
-msgid "Advanced"
+msgid "WireGuard settings"
msgstr ""
#. Title label in navigation bar
-msgctxt "wireguard-keys-nav"
+msgctxt "wireguard-settings-nav"
+msgid "WireGuard settings"
+msgstr ""
+
+msgctxt "wireguard-settings-view"
+msgid "MTU"
+msgstr ""
+
+msgctxt "wireguard-settings-view"
+msgid "Port"
+msgstr ""
+
+#. The hint displayed below the WireGuard MTU input field.
+#. Available placeholders:
+#. %(max)d - the maximum possible wireguard mtu value
+#. %(min)d - the minimum possible wireguard mtu value
+msgctxt "wireguard-settings-view"
+msgid "Set WireGuard MTU value. Valid range: %(min)d - %(max)d."
+msgstr ""
+
+#. The hint displayed below the WireGuard port selector.
+msgctxt "wireguard-settings-view"
+msgid "The automatic setting will randomly choose from a wide range of ports."
+msgstr ""
+
+msgctxt "wireguard-settings-view"
msgid "WireGuard key"
msgstr ""
+msgctxt "wireguard-settings-view"
+msgid "WireGuard settings"
+msgstr ""
+
msgid "Account authentication failed."
msgstr ""
@@ -1366,6 +1390,9 @@ msgstr ""
msgid "While connected, your real location is masked with a private and secure location in the selected region."
msgstr ""
+msgid "WireGuard MTU"
+msgstr ""
+
msgid "WireGuard error"
msgstr ""
diff --git a/gui/src/renderer/components/AdvancedSettings.tsx b/gui/src/renderer/components/AdvancedSettings.tsx
index 338a4d5b81..4cd2a567d0 100644
--- a/gui/src/renderer/components/AdvancedSettings.tsx
+++ b/gui/src/renderer/components/AdvancedSettings.tsx
@@ -1,23 +1,14 @@
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,
@@ -30,7 +21,7 @@ import * as AppButton from './AppButton';
import { AriaDescription, AriaInput, AriaInputGroup, AriaLabel } from './AriaGroup';
import * as Cell from './cell';
import CellList, { ICellListItem } from './cell/List';
-import { Layout } from './Layout';
+import { Layout, SettingsContainer } from './Layout';
import { ModalAlert, ModalAlertType, ModalContainer, ModalMessage } from './Modal';
import {
BackBarItem,
@@ -39,52 +30,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,66 +72,13 @@ 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';
return (
<ModalContainer>
<Layout>
- <StyledContainer>
+ <SettingsContainer>
<NavigationContainer>
<NavigationBar>
<NavigationItems>
@@ -245,6 +156,18 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
</Cell.Footer>
</AriaInputGroup>
+ {(window.env.platform === 'linux' || window.env.platform === 'win32') && (
+ <Cell.CellButtonGroup>
+ <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>
+ </Cell.CellButtonGroup>
+ )}
+
<AriaInputGroup>
<StyledTunnelProtocolContainer>
<StyledSelectorForFooter
@@ -268,189 +191,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.CellButtonGroup>
+ <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>
+ </Cell.CellButtonGroup>
<StyledCustomDnsSwitchContainer disabled={!this.customDnsAvailable()}>
<AriaInputGroup>
@@ -522,7 +281,7 @@ export default class AdvancedSettings extends React.Component<IProps, IState> {
</StyledCustomDnsFooter>
</StyledNavigationScrollbars>
</NavigationContainer>
- </StyledContainer>
+ </SettingsContainer>
</Layout>
{this.state.showConfirmBlockWhenDisconnectedAlert &&
@@ -644,19 +403,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 +490,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/AdvancedSettingsStyles.tsx b/gui/src/renderer/components/AdvancedSettingsStyles.tsx
index 7190a166b7..4fc08160c2 100644
--- a/gui/src/renderer/components/AdvancedSettingsStyles.tsx
+++ b/gui/src/renderer/components/AdvancedSettingsStyles.tsx
@@ -2,14 +2,9 @@ import styled from 'styled-components';
import { colors } from '../../config.json';
import BetaLabel from './BetaLabel';
import * as Cell from './cell';
-import { Container } from './Layout';
import { NavigationScrollbars } from './NavigationBar';
import Selector from './cell/Selector';
-export const StyledContainer = styled(Container)({
- backgroundColor: colors.darkBlue,
-});
-
export const StyledInputFrame = styled(Cell.InputFrame)({
flex: 0,
});
@@ -30,13 +25,6 @@ export const StyledNavigationScrollbars = styled(NavigationScrollbars)({
flex: 1,
});
-export const StyledButtonCellGroup = styled.div({
- display: 'flex',
- flexDirection: 'column',
- flex: 1,
- marginBottom: '20px',
-});
-
export const StyledNoWireguardKeyErrorContainer = styled(Cell.Footer)({
paddingBottom: 0,
});
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/Layout.tsx b/gui/src/renderer/components/Layout.tsx
index 8caf983b40..f868c7671a 100644
--- a/gui/src/renderer/components/Layout.tsx
+++ b/gui/src/renderer/components/Layout.tsx
@@ -14,6 +14,10 @@ export const Container = styled.div({
overflow: 'hidden',
});
+export const SettingsContainer = styled(Container)({
+ backgroundColor: colors.darkBlue,
+});
+
export const Layout = styled.div({
display: 'flex',
flexDirection: 'column',
diff --git a/gui/src/renderer/components/OpenVPNSettings.tsx b/gui/src/renderer/components/OpenVPNSettings.tsx
new file mode 100644
index 0000000000..72e672b681
--- /dev/null
+++ b/gui/src/renderer/components/OpenVPNSettings.tsx
@@ -0,0 +1,259 @@
+import * as React from 'react';
+import { sprintf } from 'sprintf-js';
+import styled from 'styled-components';
+import { BridgeState, RelayProtocol } from '../../shared/daemon-rpc-types';
+import { messages } from '../../shared/gettext';
+import { AriaDescription, AriaInput, AriaInputGroup, AriaLabel } from './AriaGroup';
+import * as Cell from './cell';
+import { Layout, SettingsContainer } from './Layout';
+import { ModalContainer } from './Modal';
+import {
+ BackBarItem,
+ NavigationBar,
+ NavigationContainer,
+ NavigationItems,
+ NavigationScrollbars,
+ 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 };
+}
+
+export const StyledNavigationScrollbars = styled(NavigationScrollbars)({
+ flex: 1,
+});
+
+export const StyledSelectorContainer = styled.div({
+ flex: 0,
+});
+
+export const StyledInputFrame = styled(Cell.InputFrame)({
+ flex: 0,
+});
+
+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>
+ <SettingsContainer>
+ <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>
+ </SettingsContainer>
+ </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..f60ac9fb53
--- /dev/null
+++ b/gui/src/renderer/components/WireguardSettings.tsx
@@ -0,0 +1,205 @@
+import * as React from 'react';
+import { sprintf } from 'sprintf-js';
+import styled from 'styled-components';
+import { messages } from '../../shared/gettext';
+import { AriaDescription, AriaInput, AriaInputGroup, AriaLabel } from './AriaGroup';
+import * as Cell from './cell';
+import { Layout, SettingsContainer } from './Layout';
+import {
+ BackBarItem,
+ NavigationBar,
+ NavigationContainer,
+ NavigationItems,
+ NavigationScrollbars,
+ TitleBarItem,
+} from './NavigationBar';
+import Selector, { 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 };
+}
+
+export const StyledNavigationScrollbars = styled(NavigationScrollbars)({
+ flex: 1,
+});
+
+export const StyledSelectorContainer = styled.div({
+ flex: 0,
+});
+
+export const StyledSelectorForFooter = (styled(Selector)({
+ marginBottom: 0,
+}) as unknown) as new <T>() => Selector<T>;
+
+export const StyledInputFrame = styled(Cell.InputFrame)({
+ flex: 0,
+});
+
+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>
+ <SettingsContainer>
+ <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>
+
+ <Cell.CellButtonGroup>
+ <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>
+ </Cell.CellButtonGroup>
+
+ <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>
+ </SettingsContainer>
+ </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/components/cell/CellButton.tsx b/gui/src/renderer/components/cell/CellButton.tsx
index 68f1dc1f32..993ac8bf23 100644
--- a/gui/src/renderer/components/cell/CellButton.tsx
+++ b/gui/src/renderer/components/cell/CellButton.tsx
@@ -9,7 +9,7 @@ interface IStyledCellButtonProps extends React.HTMLAttributes<HTMLButtonElement>
containedInSection: boolean;
}
-export const StyledCellButton = styled.button({}, (props: IStyledCellButtonProps) => {
+const StyledCellButton = styled.button({}, (props: IStyledCellButtonProps) => {
const backgroundColor = props.selected
? colors.green
: props.containedInSection
@@ -47,3 +47,10 @@ export const CellButton = styled(
);
}),
)({});
+
+export const CellButtonGroup = styled.div({
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ marginBottom: '20px',
+});
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'