diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2019-07-26 13:59:15 +0100 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2019-07-30 18:19:24 +0100 |
| commit | 60f4c7d207a82a2ca192a92ce7e6bb539e1b955e (patch) | |
| tree | 87f5b9af2795427deb3d6de7de6994b2cdd2c5e3 /gui/src | |
| parent | 5eb694a0468d7bcf199c58cec4b0b17529558339 (diff) | |
| download | mullvadvpn-60f4c7d207a82a2ca192a92ce7e6bb539e1b955e.tar.xz mullvadvpn-60f4c7d207a82a2ca192a92ce7e6bb539e1b955e.zip | |
Allow setting TunnelProtocol constraint from GUI
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/renderer/app.tsx | 28 | ||||
| -rw-r--r-- | gui/src/renderer/components/AdvancedSettings.tsx | 140 | ||||
| -rw-r--r-- | gui/src/renderer/components/AdvancedSettingsStyles.tsx | 3 | ||||
| -rw-r--r-- | gui/src/renderer/components/WireguardKeys.tsx | 2 | ||||
| -rw-r--r-- | gui/src/renderer/components/WireguardKeysStyles.tsx | 4 | ||||
| -rw-r--r-- | gui/src/renderer/containers/AdvancedSettingsPage.tsx | 60 | ||||
| -rw-r--r-- | gui/src/renderer/lib/relay-settings-builder.ts | 70 | ||||
| -rw-r--r-- | gui/src/renderer/redux/settings/reducers.ts | 16 |
8 files changed, 258 insertions, 65 deletions
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index d77cf65e89..f4a3e052dc 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -380,27 +380,19 @@ export default class AppRenderer { const location = normal.location; const relayLocation = location === 'any' ? 'any' : location.only; - if (tunnelProtocol === 'any' || tunnelProtocol.only === 'openvpn') { - const { port, protocol } = normal.openvpnConstraints; - actions.settings.updateRelay({ - normal: { - location: relayLocation, + const { port, protocol } = normal.openvpnConstraints; + const wireguardPort = normal.wireguardConstraints.port; + actions.settings.updateRelay({ + normal: { + location: relayLocation, + openvpn: { port: port === 'any' ? port : port.only, protocol: protocol === 'any' ? protocol : protocol.only, - tunnelProtocol: liftConstraint(tunnelProtocol), - }, - }); - } else { - const { port } = normal.wireguardConstraints; - actions.settings.updateRelay({ - normal: { - tunnelProtocol: liftConstraint(tunnelProtocol), - location: relayLocation, - port: port === 'any' ? port : port.only, - protocol: 'udp', }, - }); - } + wireguard: { port: wireguardPort === 'any' ? wireguardPort : wireguardPort.only }, + tunnelProtocol: liftConstraint(tunnelProtocol), + }, + }); } else if ('customTunnelEndpoint' in relaySettings) { const customTunnelEndpoint = relaySettings.customTunnelEndpoint; const config = customTunnelEndpoint.config; diff --git a/gui/src/renderer/components/AdvancedSettings.tsx b/gui/src/renderer/components/AdvancedSettings.tsx index 1805e07bae..f85ae547aa 100644 --- a/gui/src/renderer/components/AdvancedSettings.tsx +++ b/gui/src/renderer/components/AdvancedSettings.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { Component, View } from 'reactxp'; import { sprintf } from 'sprintf-js'; import { colors } from '../../config.json'; -import { BridgeState, RelayProtocol } from '../../shared/daemon-rpc-types'; +import { BridgeState, RelayProtocol, TunnelProtocol } from '../../shared/daemon-rpc-types'; import { messages } from '../../shared/gettext'; import styles from './AdvancedSettingsStyles'; import * as Cell from './Cell'; @@ -20,10 +20,12 @@ 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]; +const WIREUGARD_UDP_PORTS = [53]; type OptionalPort = number | undefined; type OptionalRelayProtocol = RelayProtocol | undefined; +type OptionalTunnelProtocol = TunnelProtocol | undefined; function mapPortToSelectorItem(value: number): ISelectorItem<number> { return { label: value.toString(), value }; @@ -32,16 +34,22 @@ function mapPortToSelectorItem(value: number): ISelectorItem<number> { interface IProps { enableIpv6: boolean; blockWhenDisconnected: boolean; - protocol?: RelayProtocol; + tunnelProtocol?: TunnelProtocol; + openvpn: { + protocol?: RelayProtocol; + port?: number; + }; + wireguard: { port?: number }; mssfix?: number; - port?: number; bridgeState: BridgeState; enableWireguardKeysPage: boolean; setBridgeState: (value: BridgeState) => void; setEnableIpv6: (value: boolean) => void; setBlockWhenDisconnected: (value: boolean) => void; + setTunnelProtocol: (value: OptionalTunnelProtocol) => void; setOpenVpnMssfix: (value: number | undefined) => void; - setRelayProtocolAndPort: (protocol?: RelayProtocol, port?: number) => void; + setOpenVpnRelayProtocolAndPort: (protocol?: RelayProtocol, port?: number) => void; + setWireguardRelayPort: (port?: number) => void; onViewWireguardKeys: () => void; onClose: () => void; } @@ -56,6 +64,8 @@ export default class AdvancedSettings extends Component<IProps, IState> { private portItems: { [key in RelayProtocol]: Array<ISelectorItem<OptionalPort>> }; private protocolItems: Array<ISelectorItem<OptionalRelayProtocol>>; private bridgeStateItems: Array<ISelectorItem<BridgeState>>; + private tunnelProtocolItems: Array<ISelectorItem<OptionalTunnelProtocol>>; + private wireguardPortItems: Array<ISelectorItem<OptionalPort>>; constructor(props: IProps) { super(props); @@ -70,6 +80,10 @@ export default class AdvancedSettings extends Component<IProps, IState> { 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'), @@ -85,6 +99,25 @@ export default class AdvancedSettings extends Component<IProps, IState> { }, ]; + this.tunnelProtocolItems = [ + { + label: messages.pgettext('advanced-settings-view', 'Automatic'), + value: undefined, + }, + { + label: messages.pgettext('advanced-settings-view', 'OpenVPN'), + value: 'openvpn', + }, + { + label: messages.pgettext('advanced-settings-view', 'WireGuard'), + value: 'wireguard', + }, + ]; + + this.wireguardPortItems = [automaticPort].concat( + WIREUGARD_UDP_PORTS.map(mapPortToSelectorItem), + ); + this.bridgeStateItems = [ { label: messages.pgettext('advanced-settings-view', 'Automatic'), @@ -186,33 +219,68 @@ export default class AdvancedSettings extends Component<IProps, IState> { undefined )} - <View style={styles.advanced_settings__content}> - <Selector - title={messages.pgettext('advanced-settings-view', 'Network protocols')} - values={this.protocolItems} - value={this.props.protocol} - onSelect={this.onSelectProtocol} - /> + {process.platform !== 'win32' ? ( + <View style={styles.advanced_settings__content}> + <Selector + title={messages.pgettext('advanced-settings-view', 'Tunnel protocols')} + values={this.tunnelProtocolItems} + value={this.props.tunnelProtocol} + onSelect={this.onSelectTunnelProtocol} + /> + </View> + ) : ( + undefined + )} - {this.props.protocol ? ( + {this.props.tunnelProtocol === 'openvpn' || + this.props.tunnelProtocol === undefined ? ( + <View style={styles.advanced_settings__content}> <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', '%(portType)s port'), - { - portType: this.props.protocol.toUpperCase(), - }, + title={messages.pgettext( + 'advanced-settings-view', + 'OpenVPN transport protocols', )} - values={this.portItems[this.props.protocol]} - value={this.props.port} - onSelect={this.onSelectPort} + values={this.protocolItems} + value={this.props.openvpn.protocol} + onSelect={this.onSelectOpenvpnProtocol} /> - ) : ( - undefined - )} - </View> + + {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', '%(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 + )} + </View> + ) : ( + undefined + )} + + {this.props.tunnelProtocol === 'wireguard' ? ( + <View style={styles.advanced_settings__content}> + <Selector + // 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} + /> + </View> + ) : ( + undefined + )} <Selector title={ @@ -270,7 +338,7 @@ export default class AdvancedSettings extends Component<IProps, IState> { private wireguardKeysButton() { if (this.props.enableWireguardKeysPage) { return ( - <View> + <View style={styles.advanced_settings__wgkeys_cell}> <Cell.CellButton onPress={this.props.onViewWireguardKeys}> <Cell.Label>{messages.pgettext('advanced-settings-view', 'WireGuard keys')}</Cell.Label> <Cell.Icon height={12} width={7} source="icon-chevron" /> @@ -282,12 +350,20 @@ export default class AdvancedSettings extends Component<IProps, IState> { } } - private onSelectProtocol = (protocol?: RelayProtocol) => { - this.props.setRelayProtocolAndPort(protocol); + 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 onSelectPort = (port?: number) => { - this.props.setRelayProtocolAndPort(this.props.protocol, port); + private onSelectWireguardPort = (port?: number) => { + this.props.setWireguardRelayPort(port); }; private onSelectBridgeState = (bridgeState: BridgeState) => { diff --git a/gui/src/renderer/components/AdvancedSettingsStyles.tsx b/gui/src/renderer/components/AdvancedSettingsStyles.tsx index c8eafe052f..b5fbf82c06 100644 --- a/gui/src/renderer/components/AdvancedSettingsStyles.tsx +++ b/gui/src/renderer/components/AdvancedSettingsStyles.tsx @@ -19,6 +19,9 @@ export default { advanced_settings__selector_section: Styles.createViewStyle({ marginBottom: 24, }), + advanced_settings__wgkeys_cell: Styles.createViewStyle({ + marginBottom: 24, + }), advanced_settings__cell_hover: Styles.createButtonStyle({ backgroundColor: colors.blue80, }), diff --git a/gui/src/renderer/components/WireguardKeys.tsx b/gui/src/renderer/components/WireguardKeys.tsx index dadaca4b51..ce28c28454 100644 --- a/gui/src/renderer/components/WireguardKeys.tsx +++ b/gui/src/renderer/components/WireguardKeys.tsx @@ -24,7 +24,7 @@ export default class WireguardKeys extends Component<IProps> { return ( <Layout> <Container> - <View> + <View style={styles.wgkeys}> <NavigationContainer> <NavigationBar> <BackBarItem action={this.props.onClose}> diff --git a/gui/src/renderer/components/WireguardKeysStyles.tsx b/gui/src/renderer/components/WireguardKeysStyles.tsx index 8f94bdcca6..2172b79dae 100644 --- a/gui/src/renderer/components/WireguardKeysStyles.tsx +++ b/gui/src/renderer/components/WireguardKeysStyles.tsx @@ -2,6 +2,10 @@ import { Styles } from 'reactxp'; import { colors } from '../../config.json'; export default { + wgkeys: Styles.createViewStyle({ + backgroundColor: colors.darkBlue, + flex: 1, + }), wgkeys__container: Styles.createViewStyle({ flexDirection: 'column', flex: 1, diff --git a/gui/src/renderer/containers/AdvancedSettingsPage.tsx b/gui/src/renderer/containers/AdvancedSettingsPage.tsx index 4dcb91b6b5..9440a0077b 100644 --- a/gui/src/renderer/containers/AdvancedSettingsPage.tsx +++ b/gui/src/renderer/containers/AdvancedSettingsPage.tsx @@ -2,7 +2,7 @@ import { goBack, push } from 'connected-react-router'; import log from 'electron-log'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; -import { BridgeState, RelayProtocol } from '../../shared/daemon-rpc-types'; +import { BridgeState, RelayProtocol, TunnelProtocol } from '../../shared/daemon-rpc-types'; import AdvancedSettings from '../components/AdvancedSettings'; import RelaySettingsBuilder from '../lib/relay-settings-builder'; @@ -26,14 +26,26 @@ const mapStateToProps = (state: IReduxState) => { const mapRelaySettingsToProtocolAndPort = (relaySettings: RelaySettingsRedux) => { if ('normal' in relaySettings) { - const { protocol, port } = relaySettings.normal; + const { tunnelProtocol, openvpn, wireguard } = relaySettings.normal; return { - protocol: protocol === 'any' ? undefined : protocol, - port: port === 'any' ? undefined : port, + 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, }; + // 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) { - const { protocol, port } = relaySettings.customTunnelEndpoint; - return { protocol, port }; + return { + openvpn: { + protocol: undefined, + port: undefined, + }, + wireguard: { port: undefined }, + tunnelProtocol: undefined, + }; } else { throw new Error('Unknown type of relay settings.'); } @@ -45,7 +57,7 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, props: ISharedRouteProps) = onClose: () => { history.goBack(); }, - setRelayProtocolAndPort: async (protocol?: RelayProtocol, port?: number) => { + setOpenVpnRelayProtocolAndPort: async (protocol?: RelayProtocol, port?: number) => { const relayUpdate = RelaySettingsBuilder.normal() .tunnel.openvpn((openvpn) => { if (protocol) { @@ -69,6 +81,40 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, props: ISharedRouteProps) = } }, + 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() + .tunnel.tunnelProtocol((config) => { + if (tunnelProtocol) { + config.tunnelProtocol.exact(tunnelProtocol); + } else { + config.tunnelProtocol.any(); + } + }) + .build(); + try { + await props.app.updateRelaySettings(relayUpdate); + } catch (e) { + log.error('Failed to update tunnel protocol constraints', e.message); + } + }, + setEnableIpv6: async (enableIpv6: boolean) => { try { await props.app.setEnableIpv6(enableIpv6); diff --git a/gui/src/renderer/lib/relay-settings-builder.ts b/gui/src/renderer/lib/relay-settings-builder.ts index bbf85b1fed..08ecef720e 100644 --- a/gui/src/renderer/lib/relay-settings-builder.ts +++ b/gui/src/renderer/lib/relay-settings-builder.ts @@ -1,9 +1,11 @@ import { IOpenVpnConstraints, + IWireguardConstraints, RelayLocation, RelayProtocol, RelaySettingsNormalUpdate, RelaySettingsUpdate, + TunnelProtocol, } from '../../shared/daemon-rpc-types'; interface ILocationBuilder<Self> { @@ -24,11 +26,24 @@ interface IOpenVPNConfigurator { protocol: IExactOrAny<RelayProtocol, IOpenVPNConfigurator>; } +interface IWireguardConfigurator { + port: IExactOrAny<number, IWireguardConfigurator>; +} + +interface ITunnelProtocolConfigurator { + tunnelProtocol: IExactOrAny<TunnelProtocol, ITunnelProtocolConfigurator>; +} + interface ITunnelBuilder { openvpn( configurator: (openVpnConfigurator: IOpenVPNConfigurator) => void, ): NormalRelaySettingsBuilder; - any(): NormalRelaySettingsBuilder; + wireguard( + configurator: (wireguardConfigurator: IWireguardConfigurator) => void, + ): NormalRelaySettingsBuilder; + tunnelProtocol( + configurator: (tunnelProtocolConfigurator: ITunnelProtocolConfigurator) => void, + ): NormalRelaySettingsBuilder; } class NormalRelaySettingsBuilder { @@ -91,6 +106,22 @@ class NormalRelaySettingsBuilder { } }; + const updateWireguard = (next: Partial<IWireguardConstraints>) => { + if (this.payload.wireguardConstraints === undefined) { + this.payload.wireguardConstraints = next; + } else { + const prev = this.payload.wireguardConstraints; + this.payload.wireguardConstraints = { + ...prev, + ...next, + }; + } + }; + + const updateTunnelProtocol = (next: { only: TunnelProtocol } | 'any' | undefined) => { + this.payload.tunnelProtocol = next; + }; + return { openvpn: (configurator: (configurator: IOpenVPNConfigurator) => void) => { const openvpnBuilder: IOpenVPNConfigurator = { @@ -120,8 +151,41 @@ class NormalRelaySettingsBuilder { return this; }, - any: () => { - this.payload.tunnelProtocol = 'any'; + + wireguard: (configurator: (configurator: IWireguardConfigurator) => void) => { + const wireguardBuilder: IWireguardConfigurator = { + get port() { + const apply = (port: 'any' | { only: number }) => { + updateWireguard({ port }); + return this; + }; + return { + exact: (value: number) => apply({ only: value }), + any: () => apply('any'), + }; + }, + }; + configurator(wireguardBuilder); + return this; + }, + + tunnelProtocol: (configurator: (configurator: ITunnelProtocolConfigurator) => void) => { + const tunnelProtocolBuilder = { + get tunnelProtocol() { + return { + exact: (value: TunnelProtocol) => { + updateTunnelProtocol({ only: value }); + return this; + }, + any: () => { + updateTunnelProtocol('any'); + return this; + }, + }; + }, + }; + + configurator(tunnelProtocolBuilder); return this; }, }; diff --git a/gui/src/renderer/redux/settings/reducers.ts b/gui/src/renderer/redux/settings/reducers.ts index e41750b496..e90022062c 100644 --- a/gui/src/renderer/redux/settings/reducers.ts +++ b/gui/src/renderer/redux/settings/reducers.ts @@ -14,8 +14,13 @@ export type RelaySettingsRedux = normal: { tunnelProtocol: 'any' | TunnelProtocol; location: 'any' | RelayLocation; - port: 'any' | number; - protocol: 'any' | RelayProtocol; + openvpn: { + port: 'any' | number; + protocol: 'any' | RelayProtocol; + }; + wireguard: { + port: 'any' | number; + }; }; } | { @@ -111,8 +116,11 @@ const initialState: ISettingsReduxState = { normal: { location: 'any', tunnelProtocol: 'any', - port: 'any', - protocol: 'any', + wireguard: { port: 'any' }, + openvpn: { + port: 'any', + protocol: 'any', + }, }, }, relayLocations: [], |
