summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2023-10-26 01:13:39 +0200
committerDavid Lönnhager <david.l@mullvad.net>2023-10-31 00:45:17 +0100
commitfbc8c1675700e1e87d9282ee288e6c0b72c1c7aa (patch)
tree85c4cb1d2a5a43826e8f3a0a2552a177e58bbced /gui/src
parente02d812d55064fc114d38edbdcbbeda5aca6a6b7 (diff)
downloadmullvadvpn-fbc8c1675700e1e87d9282ee288e6c0b72c1c7aa.tar.xz
mullvadvpn-fbc8c1675700e1e87d9282ee288e6c0b72c1c7aa.zip
Remove RelaySettingsUpdate from gui/
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/main/daemon-rpc.ts80
-rw-r--r--gui/src/main/settings.ts4
-rw-r--r--gui/src/renderer/app.tsx3
-rw-r--r--gui/src/renderer/components/Filter.tsx12
-rw-r--r--gui/src/renderer/components/OpenVpnSettings.tsx35
-rw-r--r--gui/src/renderer/components/VpnSettings.tsx37
-rw-r--r--gui/src/renderer/components/WireguardSettings.tsx53
-rw-r--r--gui/src/renderer/components/select-location/SelectLocation.tsx16
-rw-r--r--gui/src/renderer/components/select-location/select-location-hooks.ts61
-rw-r--r--gui/src/renderer/lib/constraint-updater.ts111
-rw-r--r--gui/src/shared/daemon-rpc-types.ts21
-rw-r--r--gui/src/shared/ipc-schema.ts4
-rw-r--r--gui/src/shared/relay-settings-builder.ts189
13 files changed, 234 insertions, 392 deletions
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts
index 288bbfd7fc..f1fba53d55 100644
--- a/gui/src/main/daemon-rpc.ts
+++ b/gui/src/main/daemon-rpc.ts
@@ -41,6 +41,7 @@ import {
IRelayListCountry,
IRelayListHostname,
IRelayListWithEndpointData,
+ IRelaySettingsNormal,
ISettings,
ITunnelOptions,
ITunnelStateRelayInfo,
@@ -58,12 +59,12 @@ import {
RelayLocationGeographical,
RelayProtocol,
RelaySettings,
- RelaySettingsUpdate,
TunnelParameterError,
TunnelProtocol,
TunnelState,
TunnelType,
VoucherResponse,
+ wrapConstraint,
} from '../shared/daemon-rpc-types';
import log from '../shared/logging';
import { ManagementServiceClient } from './management_interface/management_interface_grpc_pb';
@@ -297,52 +298,14 @@ export class DaemonRpc {
}
// TODO: Custom tunnel configurations are not supported by the GUI.
- public async updateRelaySettings(relaySettings: RelaySettingsUpdate): Promise<void> {
+ public async updateRelaySettings(relaySettings: RelaySettings): Promise<void> {
if ('normal' in relaySettings) {
- const settingsUpdate = relaySettings.normal;
- const grpcRelaySettings = new grpcTypes.RelaySettingsUpdate();
+ const normalSettings = relaySettings.normal;
+ const grpcRelaySettings = new grpcTypes.RelaySettings();
+ grpcRelaySettings.setNormal(convertToRelayConstraints(normalSettings));
- const normalUpdate = new grpcTypes.NormalRelaySettingsUpdate();
-
- if (settingsUpdate.tunnelProtocol) {
- const tunnelTypeUpdate = new grpcTypes.TunnelTypeUpdate();
- if (settingsUpdate.tunnelProtocol !== 'any') {
- tunnelTypeUpdate.setTunnelType(convertToTunnelType(settingsUpdate.tunnelProtocol.only));
- }
- normalUpdate.setTunnelType(tunnelTypeUpdate);
- }
-
- if (settingsUpdate.location) {
- normalUpdate.setLocation(convertToLocation(liftConstraint(settingsUpdate.location)));
- }
-
- if (settingsUpdate.wireguardConstraints) {
- normalUpdate.setWireguardConstraints(
- convertToWireguardConstraints(settingsUpdate.wireguardConstraints),
- );
- }
-
- if (settingsUpdate.openvpnConstraints) {
- normalUpdate.setOpenvpnConstraints(
- convertToOpenVpnConstraints(settingsUpdate.openvpnConstraints),
- );
- }
-
- if (settingsUpdate.providers) {
- const providerUpdate = new grpcTypes.ProviderUpdate();
- providerUpdate.setProvidersList(settingsUpdate.providers);
- normalUpdate.setProviders(providerUpdate);
- }
-
- if (settingsUpdate.ownership !== undefined) {
- const ownershipUpdate = new grpcTypes.OwnershipUpdate();
- ownershipUpdate.setOwnership(convertToOwnership(settingsUpdate.ownership));
- normalUpdate.setOwnership(ownershipUpdate);
- }
-
- grpcRelaySettings.setNormal(normalUpdate);
- await this.call<grpcTypes.RelaySettingsUpdate, Empty>(
- this.client.updateRelaySettings,
+ await this.call<grpcTypes.RelaySettings, Empty>(
+ this.client.setRelaySettings,
grpcRelaySettings,
);
}
@@ -1148,7 +1111,7 @@ function convertFromRelaySettings(
case grpcTypes.RelaySettings.EndpointCase.NORMAL: {
const normal = relaySettings.getNormal()!;
const locationConstraint = convertFromLocationConstraint(normal.getLocation());
- const location = locationConstraint ? { only: locationConstraint } : 'any';
+ const location = wrapConstraint(locationConstraint);
// `getTunnelType()` is not falsy if type is 'any'
const tunnelProtocol = convertFromTunnelTypeConstraint(
normal.hasTunnelType() ? normal.getTunnelType() : undefined,
@@ -1184,7 +1147,7 @@ function convertFromBridgeSettings(bridgeSettings: grpcTypes.BridgeSettings): Br
const locationConstraint = convertFromLocationConstraint(
bridgeSettings.getNormal()?.getLocation(),
);
- const location = locationConstraint ? { only: locationConstraint } : 'any';
+ const location = wrapConstraint(locationConstraint);
const providers = normalSettings.providersList;
const ownership = convertFromOwnership(normalSettings.ownership);
return {
@@ -1475,7 +1438,7 @@ function convertFromWireguardConstraints(
const entryLocation = constraints.getEntryLocation();
if (entryLocation) {
const location = convertFromLocationConstraint(entryLocation);
- result.entryLocation = location ? { only: location } : 'any';
+ result.entryLocation = wrapConstraint(location);
}
return result;
@@ -1505,6 +1468,27 @@ function convertFromConstraint<T>(value: T | undefined): Constraint<T> {
}
}
+function convertToRelayConstraints(
+ constraints: IRelaySettingsNormal<IOpenVpnConstraints, IWireguardConstraints>,
+): grpcTypes.NormalRelaySettings {
+ const relayConstraints = new grpcTypes.NormalRelaySettings();
+
+ if (constraints.tunnelProtocol !== 'any') {
+ relayConstraints.setTunnelType(convertToTunnelType(constraints.tunnelProtocol.only));
+ }
+ relayConstraints.setLocation(convertToLocation(liftConstraint(constraints.location)));
+ relayConstraints.setWireguardConstraints(
+ convertToWireguardConstraints(constraints.wireguardConstraints),
+ );
+ relayConstraints.setOpenvpnConstraints(
+ convertToOpenVpnConstraints(constraints.openvpnConstraints),
+ );
+ relayConstraints.setProvidersList(constraints.providers);
+ relayConstraints.setOwnership(convertToOwnership(constraints.ownership));
+
+ return relayConstraints;
+}
+
function convertToNormalBridgeSettings(
constraints: IBridgeConstraints,
): grpcTypes.BridgeSettings.BridgeConstraints {
diff --git a/gui/src/main/settings.ts b/gui/src/main/settings.ts
index 3016e75289..3f04666df6 100644
--- a/gui/src/main/settings.ts
+++ b/gui/src/main/settings.ts
@@ -56,8 +56,8 @@ export default class Settings implements Readonly<ISettings> {
IpcMainEventChannel.settings.handleSetWireguardQuantumResistant((quantumResistant?: boolean) =>
this.daemonRpc.setWireguardQuantumResistant(quantumResistant),
);
- IpcMainEventChannel.settings.handleUpdateRelaySettings((update) =>
- this.daemonRpc.updateRelaySettings(update),
+ IpcMainEventChannel.settings.handleUpdateRelaySettings((relaySettings) =>
+ this.daemonRpc.updateRelaySettings(relaySettings),
);
IpcMainEventChannel.settings.handleUpdateBridgeSettings((bridgeSettings) => {
return this.daemonRpc.setBridgeSettings(bridgeSettings);
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index bab17524d6..bdfe272061 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -23,7 +23,6 @@ import {
liftConstraint,
ObfuscationSettings,
RelaySettings,
- RelaySettingsUpdate,
TunnelState,
} from '../shared/daemon-rpc-types';
import { messages, relayLocations } from '../shared/gettext';
@@ -304,7 +303,7 @@ export default class AppRenderer {
public connectTunnel = () => IpcRendererEventChannel.tunnel.connect();
public disconnectTunnel = () => IpcRendererEventChannel.tunnel.disconnect();
public reconnectTunnel = () => IpcRendererEventChannel.tunnel.reconnect();
- public updateRelaySettings = (relaySettings: RelaySettingsUpdate) =>
+ public updateRelaySettings = (relaySettings: RelaySettings) =>
IpcRendererEventChannel.settings.updateRelaySettings(relaySettings);
public updateBridgeSettings = (bridgeSettings: BridgeSettings) =>
IpcRendererEventChannel.settings.updateBridgeSettings(bridgeSettings);
diff --git a/gui/src/renderer/components/Filter.tsx b/gui/src/renderer/components/Filter.tsx
index 2cbc9ab239..d989cbca95 100644
--- a/gui/src/renderer/components/Filter.tsx
+++ b/gui/src/renderer/components/Filter.tsx
@@ -4,7 +4,7 @@ import styled from 'styled-components';
import { colors } from '../../config.json';
import { Ownership } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
-import { useAppContext } from '../context';
+import { useRelaySettingsUpdater } from '../lib/constraint-updater';
import {
EndpointType,
filterLocations,
@@ -38,7 +38,7 @@ const StyledNavigationScrollbars = styled(NavigationScrollbars)({
export default function Filter() {
const history = useHistory();
- const { updateRelaySettings } = useAppContext();
+ const relaySettingsUpdater = useRelaySettingsUpdater();
const initialProviders = useSelector(providersSelector);
const [providers, setProviders] = useState<Record<string, boolean>>(initialProviders);
@@ -69,9 +69,13 @@ export default function Filter() {
// Applies the changes by sending them to the daemon.
const onApply = useCallback(async () => {
- await updateRelaySettings({ normal: { providers: formattedProviderList, ownership } });
+ await relaySettingsUpdater((settings) => {
+ settings.providers = formattedProviderList;
+ settings.ownership = ownership;
+ return settings;
+ });
history.pop();
- }, [formattedProviderList, ownership, history, updateRelaySettings]);
+ }, [formattedProviderList, ownership, history, relaySettingsUpdater]);
return (
<BackAction action={history.pop}>
diff --git a/gui/src/renderer/components/OpenVpnSettings.tsx b/gui/src/renderer/components/OpenVpnSettings.tsx
index dc14cd979f..c848f5688b 100644
--- a/gui/src/renderer/components/OpenVpnSettings.tsx
+++ b/gui/src/renderer/components/OpenVpnSettings.tsx
@@ -3,12 +3,17 @@ import { sprintf } from 'sprintf-js';
import styled from 'styled-components';
import { strings } from '../../config.json';
-import { BridgeState, RelayProtocol, TunnelProtocol } from '../../shared/daemon-rpc-types';
+import {
+ BridgeState,
+ RelayProtocol,
+ TunnelProtocol,
+ wrapConstraint,
+} from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
import log from '../../shared/logging';
-import RelaySettingsBuilder from '../../shared/relay-settings-builder';
import { removeNonNumericCharacters } from '../../shared/string-helpers';
import { useAppContext } from '../context';
+import { useRelaySettingsUpdater } from '../lib/constraint-updater';
import { useHistory } from '../lib/history';
import { formatHtml } from '../lib/html-formatter';
import { useBoolean } from '../lib/utilityHooks';
@@ -177,34 +182,24 @@ function TransportProtocolSelector() {
}
function useProtocolAndPortUpdater() {
- const { updateRelaySettings } = useAppContext();
+ const relaySettingsUpdater = useRelaySettingsUpdater();
const updater = useCallback(
async (protocol: RelayProtocol | null, port?: number | null) => {
- const relayUpdate = RelaySettingsBuilder.normal()
- .tunnel.openvpn((openvpn) => {
- if (protocol) {
- openvpn.protocol.exact(protocol);
- } else {
- openvpn.protocol.any();
- }
-
+ try {
+ await relaySettingsUpdater((settings) => {
+ settings.openvpnConstraints.protocol = wrapConstraint(protocol);
if (port) {
- openvpn.port.exact(port);
- } else {
- openvpn.port.any();
+ settings.openvpnConstraints.port = wrapConstraint(port);
}
- })
- .build();
-
- try {
- await updateRelaySettings(relayUpdate);
+ return settings;
+ });
} catch (e) {
const error = e as Error;
log.error('Failed to update relay settings', error.message);
}
},
- [updateRelaySettings],
+ [relaySettingsUpdater],
);
return updater;
diff --git a/gui/src/renderer/components/VpnSettings.tsx b/gui/src/renderer/components/VpnSettings.tsx
index c884db3e5e..0aa90af8c3 100644
--- a/gui/src/renderer/components/VpnSettings.tsx
+++ b/gui/src/renderer/components/VpnSettings.tsx
@@ -3,11 +3,11 @@ import { sprintf } from 'sprintf-js';
import styled from 'styled-components';
import { colors, strings } from '../../config.json';
-import { IDnsOptions, TunnelProtocol } from '../../shared/daemon-rpc-types';
+import { IDnsOptions, TunnelProtocol, wrapConstraint } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
import log from '../../shared/logging';
-import RelaySettingsBuilder from '../../shared/relay-settings-builder';
import { useAppContext } from '../context';
+import { useRelaySettingsUpdater } from '../lib/constraint-updater';
import { useHistory } from '../lib/history';
import { formatHtml } from '../lib/html-formatter';
import { RoutePath } from '../lib/routes';
@@ -663,25 +663,22 @@ function TunnelProtocolSetting() {
const tunnelProtocol = useSelector((state) =>
mapRelaySettingsToProtocol(state.settings.relaySettings),
);
- const { updateRelaySettings } = useAppContext();
+ const relaySettingsUpdater = useRelaySettingsUpdater();
- const setTunnelProtocol = useCallback(async (tunnelProtocol: TunnelProtocol | null) => {
- const relayUpdate = RelaySettingsBuilder.normal()
- .tunnel.tunnelProtocol((config) => {
- if (tunnelProtocol !== null) {
- config.tunnelProtocol.exact(tunnelProtocol);
- } else {
- config.tunnelProtocol.any();
- }
- })
- .build();
- try {
- await updateRelaySettings(relayUpdate);
- } catch (e) {
- const error = e as Error;
- log.error('Failed to update tunnel protocol constraints', error.message);
- }
- }, []);
+ const setTunnelProtocol = useCallback(
+ async (tunnelProtocol: TunnelProtocol | null) => {
+ try {
+ await relaySettingsUpdater((settings) => ({
+ ...settings,
+ tunnelProtocol: wrapConstraint(tunnelProtocol),
+ }));
+ } catch (e) {
+ const error = e as Error;
+ log.error('Failed to update tunnel protocol constraints', error.message);
+ }
+ },
+ [relaySettingsUpdater],
+ );
const tunnelProtocolItems: Array<SelectorItem<TunnelProtocol>> = useMemo(
() => [
diff --git a/gui/src/renderer/components/WireguardSettings.tsx b/gui/src/renderer/components/WireguardSettings.tsx
index e0e73f230e..7cd93b98bd 100644
--- a/gui/src/renderer/components/WireguardSettings.tsx
+++ b/gui/src/renderer/components/WireguardSettings.tsx
@@ -8,12 +8,13 @@ import {
liftConstraint,
LiftedConstraint,
ObfuscationType,
+ wrapConstraint,
} from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
import log from '../../shared/logging';
import { removeNonNumericCharacters } from '../../shared/string-helpers';
import { useAppContext } from '../context';
-import { createWireguardRelayUpdater } from '../lib/constraint-updater';
+import { useRelaySettingsUpdater } from '../lib/constraint-updater';
import { useHistory } from '../lib/history';
import { useBoolean } from '../lib/utilityHooks';
import { useSelector } from '../redux/store';
@@ -132,7 +133,7 @@ export default function WireguardSettings() {
function PortSelector() {
const relaySettings = useSelector((state) => state.settings.relaySettings);
- const { updateRelaySettings } = useAppContext();
+ const relaySettingsUpdater = useRelaySettingsUpdater();
const allowedPortRanges = useSelector((state) => state.settings.wireguardEndpointData.portRanges);
const wireguardPortItems = useMemo<Array<SelectorItem<number>>>(
@@ -147,23 +148,17 @@ function PortSelector() {
const setWireguardPort = useCallback(
async (port: number | null) => {
- const relayUpdate = createWireguardRelayUpdater(relaySettings)
- .tunnel.wireguard((wireguard) => {
- if (port !== null) {
- wireguard.port.exact(port);
- } else {
- wireguard.port.any();
- }
- })
- .build();
try {
- await updateRelaySettings(relayUpdate);
+ await relaySettingsUpdater((settings) => {
+ settings.wireguardConstraints.port = wrapConstraint(port);
+ return settings;
+ });
} catch (e) {
const error = e as Error;
log.error('Failed to update relay settings', error.message);
}
},
- [relaySettings],
+ [relaySettingsUpdater],
);
const parseValue = useCallback((port: string) => parseInt(port), []);
@@ -288,7 +283,7 @@ function Udp2tcpPortSetting() {
...obfuscationSettings,
udp2tcpSettings: {
...obfuscationSettings.udp2tcpSettings,
- port: port === 'any' ? 'any' : { only: port },
+ port: wrapConstraint(port),
},
});
},
@@ -324,7 +319,7 @@ function Udp2tcpPortSetting() {
function MultihopSetting() {
const relaySettings = useSelector((state) => state.settings.relaySettings);
- const { updateRelaySettings } = useAppContext();
+ const relaySettingsUpdater = useRelaySettingsUpdater();
const multihop = 'normal' in relaySettings ? relaySettings.normal.wireguard.useMultihop : false;
@@ -332,17 +327,17 @@ function MultihopSetting() {
const setMultihopImpl = useCallback(
async (enabled: boolean) => {
- const relayUpdate = createWireguardRelayUpdater(relaySettings)
- .tunnel.wireguard((wireguard) => wireguard.useMultihop(enabled))
- .build();
try {
- await updateRelaySettings(relayUpdate);
+ await relaySettingsUpdater((settings) => {
+ settings.wireguardConstraints.useMultihop = enabled;
+ return settings;
+ });
} catch (e) {
const error = e as Error;
log.error('Failed to update WireGuard multihop settings', error.message);
}
},
- [relaySettings, updateRelaySettings],
+ [relaySettingsUpdater],
);
const setMultihop = useCallback(
@@ -416,7 +411,7 @@ function MultihopSetting() {
}
function IpVersionSetting() {
- const { updateRelaySettings } = useAppContext();
+ const relaySettingsUpdater = useRelaySettingsUpdater();
const relaySettings = useSelector((state) => state.settings.relaySettings);
const ipVersion = useMemo(() => {
const ipVersion = 'normal' in relaySettings ? relaySettings.normal.wireguard.ipVersion : 'any';
@@ -439,23 +434,17 @@ function IpVersionSetting() {
const setIpVersion = useCallback(
async (ipVersion: IpVersion | null) => {
- const relayUpdate = createWireguardRelayUpdater(relaySettings)
- .tunnel.wireguard((wireguard) => {
- if (ipVersion !== null) {
- wireguard.ipVersion.exact(ipVersion);
- } else {
- wireguard.ipVersion.any();
- }
- })
- .build();
try {
- await updateRelaySettings(relayUpdate);
+ await relaySettingsUpdater((settings) => {
+ settings.wireguardConstraints.ipVersion = wrapConstraint(ipVersion);
+ return settings;
+ });
} catch (e) {
const error = e as Error;
log.error('Failed to update relay settings', error.message);
}
},
- [relaySettings, updateRelaySettings],
+ [relaySettingsUpdater],
);
return (
diff --git a/gui/src/renderer/components/select-location/SelectLocation.tsx b/gui/src/renderer/components/select-location/SelectLocation.tsx
index c812d84835..e09823586f 100644
--- a/gui/src/renderer/components/select-location/SelectLocation.tsx
+++ b/gui/src/renderer/components/select-location/SelectLocation.tsx
@@ -4,7 +4,7 @@ import { sprintf } from 'sprintf-js';
import { colors } from '../../../config.json';
import { Ownership } from '../../../shared/daemon-rpc-types';
import { messages } from '../../../shared/gettext';
-import { useAppContext } from '../../context';
+import { useRelaySettingsUpdater } from '../../lib/constraint-updater';
import { filterSpecialLocations } from '../../lib/filter-locations';
import { useHistory } from '../../lib/history';
import { formatHtml } from '../../lib/html-formatter';
@@ -57,7 +57,7 @@ import { SpacePreAllocationView } from './SpacePreAllocationView';
export default function SelectLocation() {
const history = useHistory();
- const { updateRelaySettings } = useAppContext();
+ const relaySettingsUpdater = useRelaySettingsUpdater();
const {
saveScrollPosition,
resetScrollPositions,
@@ -85,13 +85,17 @@ export default function SelectLocation() {
const onClearProviders = useCallback(async () => {
resetScrollPositions();
- await updateRelaySettings({ normal: { providers: [] } });
- }, [resetScrollPositions]);
+ if (relaySettings) {
+ await relaySettingsUpdater((settings) => ({ ...settings, providers: [] }));
+ }
+ }, [relaySettingsUpdater, resetScrollPositions, relaySettings]);
const onClearOwnership = useCallback(async () => {
resetScrollPositions();
- await updateRelaySettings({ normal: { ownership: Ownership.any } });
- }, [resetScrollPositions]);
+ if (relaySettings) {
+ await relaySettingsUpdater((settings) => ({ ...settings, ownership: Ownership.any }));
+ }
+ }, [relaySettingsUpdater, resetScrollPositions, relaySettings]);
const changeLocationType = useCallback(
(locationType: LocationType) => {
diff --git a/gui/src/renderer/components/select-location/select-location-hooks.ts b/gui/src/renderer/components/select-location/select-location-hooks.ts
index 105e701524..0490799123 100644
--- a/gui/src/renderer/components/select-location/select-location-hooks.ts
+++ b/gui/src/renderer/components/select-location/select-location-hooks.ts
@@ -4,30 +4,33 @@ import BridgeSettingsBuilder from '../../../shared/bridge-settings-builder';
import {
BridgeSettings,
RelayLocation,
- RelaySettingsUpdate,
+ RelaySettings,
+ wrapConstraint,
} from '../../../shared/daemon-rpc-types';
import log from '../../../shared/logging';
-import RelaySettingsBuilder from '../../../shared/relay-settings-builder';
import { useAppContext } from '../../context';
-import { createWireguardRelayUpdater } from '../../lib/constraint-updater';
+import { useRelaySettingsModifier } from '../../lib/constraint-updater';
import { useHistory } from '../../lib/history';
-import { useSelector } from '../../redux/store';
import { LocationType, SpecialBridgeLocationType } from './select-location-types';
import { useSelectLocationContext } from './SelectLocationContainer';
export function useOnSelectExitLocation() {
const onSelectLocation = useOnSelectLocation();
const history = useHistory();
+ const relaySettingsModifier = useRelaySettingsModifier();
const { connectTunnel } = useAppContext();
const onSelectRelay = useCallback(
async (relayLocation: RelayLocation) => {
+ const settings = relaySettingsModifier((settings) => ({
+ ...settings,
+ location: wrapConstraint(relayLocation),
+ }));
history.pop();
- const relayUpdate = RelaySettingsBuilder.normal().location.fromRaw(relayLocation).build();
- await onSelectLocation(relayUpdate);
+ await onSelectLocation({ normal: settings });
await connectTunnel();
},
- [history],
+ [history, relaySettingsModifier],
);
const onSelectSpecial = useCallback((_location: undefined) => {
@@ -40,23 +43,31 @@ export function useOnSelectExitLocation() {
export function useOnSelectEntryLocation() {
const onSelectLocation = useOnSelectLocation();
const { setLocationType } = useSelectLocationContext();
- const baseRelaySettings = useSelector((state) => state.settings.relaySettings);
+ const relaySettingsModifier = useRelaySettingsModifier();
- const onSelectRelay = useCallback(async (entryLocation: RelayLocation) => {
- setLocationType(LocationType.exit);
- const relayUpdate = createWireguardRelayUpdater(baseRelaySettings)
- .tunnel.wireguard((wireguard) => wireguard.entryLocation.exact(entryLocation))
- .build();
- await onSelectLocation(relayUpdate);
- }, []);
+ const onSelectRelay = useCallback(
+ async (entryLocation: RelayLocation) => {
+ setLocationType(LocationType.exit);
+ const settings = relaySettingsModifier((settings) => {
+ settings.wireguardConstraints.entryLocation = wrapConstraint(entryLocation);
+ return settings;
+ });
+ await onSelectLocation({ normal: settings });
+ },
+ [relaySettingsModifier],
+ );
- const onSelectSpecial = useCallback(async (_location: 'any') => {
- setLocationType(LocationType.exit);
- const relayUpdate = createWireguardRelayUpdater(baseRelaySettings)
- .tunnel.wireguard((wireguard) => wireguard.entryLocation.any())
- .build();
- await onSelectLocation(relayUpdate);
- }, []);
+ const onSelectSpecial = useCallback(
+ async (_location: 'any') => {
+ setLocationType(LocationType.exit);
+ const settings = relaySettingsModifier((settings) => {
+ settings.wireguardConstraints.entryLocation = 'any';
+ return settings;
+ });
+ await onSelectLocation({ normal: settings });
+ },
+ [relaySettingsModifier],
+ );
return [onSelectRelay, onSelectSpecial] as const;
}
@@ -64,12 +75,12 @@ export function useOnSelectEntryLocation() {
function useOnSelectLocation() {
const { updateRelaySettings } = useAppContext();
- return useCallback(async (relayUpdate: RelaySettingsUpdate) => {
+ return useCallback(async (relaySettings: RelaySettings) => {
try {
- await updateRelaySettings(relayUpdate);
+ await updateRelaySettings(relaySettings);
} catch (e) {
const error = e as Error;
- log.error(`Failed to select the exit location: ${error.message}`);
+ log.error(`Failed to select the location: ${error.message}`);
}
}, []);
}
diff --git a/gui/src/renderer/lib/constraint-updater.ts b/gui/src/renderer/lib/constraint-updater.ts
index 3ebbcccbc0..4acb351335 100644
--- a/gui/src/renderer/lib/constraint-updater.ts
+++ b/gui/src/renderer/lib/constraint-updater.ts
@@ -1,36 +1,89 @@
-import RelaySettingsBuilder from '../../shared/relay-settings-builder';
-import { RelaySettingsRedux } from '../redux/settings/reducers';
+import { useCallback } from 'react';
-export function createWireguardRelayUpdater(
- relaySettings: RelaySettingsRedux,
-): ReturnType<typeof RelaySettingsBuilder['normal']> {
- if ('normal' in relaySettings) {
- const constraints = relaySettings.normal.wireguard;
+import {
+ IOpenVpnConstraints,
+ IRelaySettingsNormal,
+ IWireguardConstraints,
+ Ownership,
+ wrapConstraint,
+} from '../../shared/daemon-rpc-types';
+import { useAppContext } from '../context';
+import { NormalRelaySettingsRedux } from '../redux/settings/reducers';
+import { useNormalRelaySettings } from './utilityHooks';
- const relayUpdate = RelaySettingsBuilder.normal().tunnel.wireguard((wireguard) => {
- if (constraints.port === 'any') {
- wireguard.port.any();
- } else {
- wireguard.port.exact(constraints.port);
- }
+export function wrapRelaySettingsOrDefault(
+ relaySettings?: NormalRelaySettingsRedux,
+): IRelaySettingsNormal<IOpenVpnConstraints, IWireguardConstraints> {
+ if (relaySettings) {
+ const openvpnPort = wrapConstraint(relaySettings.openvpn.port);
+ const openvpnProtocol = wrapConstraint(relaySettings.openvpn.protocol);
+ const wgPort = wrapConstraint(relaySettings.wireguard.port);
+ const wgIpVersion = wrapConstraint(relaySettings.wireguard.ipVersion);
+ const wgEntryLocation = wrapConstraint(relaySettings.wireguard.entryLocation);
+ const location = wrapConstraint(relaySettings.location);
+ const tunnelProtocol = wrapConstraint(relaySettings.tunnelProtocol);
- if (constraints.ipVersion === 'any') {
- wireguard.ipVersion.any();
- } else {
- wireguard.ipVersion.exact(constraints.ipVersion);
- }
+ return {
+ providers: [...relaySettings.providers],
+ ownership: relaySettings.ownership,
+ tunnelProtocol,
+ openvpnConstraints: {
+ port: openvpnPort,
+ protocol: openvpnProtocol,
+ },
+ wireguardConstraints: {
+ port: wgPort,
+ ipVersion: wgIpVersion,
+ useMultihop: relaySettings.wireguard.useMultihop,
+ entryLocation: wgEntryLocation,
+ },
+ location,
+ };
+ }
+
+ return {
+ location: 'any',
+ tunnelProtocol: 'any',
+ providers: [],
+ ownership: Ownership.any,
+ openvpnConstraints: {
+ port: 'any',
+ protocol: 'any',
+ },
+ wireguardConstraints: {
+ port: 'any',
+ ipVersion: 'any',
+ useMultihop: false,
+ entryLocation: 'any',
+ },
+ };
+}
- wireguard.useMultihop(constraints.useMultihop);
+type UpdateFunction = (
+ settings: IRelaySettingsNormal<IOpenVpnConstraints, IWireguardConstraints>,
+) => IRelaySettingsNormal<IOpenVpnConstraints, IWireguardConstraints>;
- if (constraints.entryLocation === 'any') {
- wireguard.entryLocation.any();
- } else if (constraints.entryLocation !== undefined) {
- wireguard.entryLocation.exact(constraints.entryLocation);
- }
- });
+export function useRelaySettingsModifier() {
+ const relaySettings = useNormalRelaySettings();
- return relayUpdate;
- } else {
- return RelaySettingsBuilder.normal();
- }
+ return useCallback(
+ (fn: UpdateFunction) => {
+ const settings = wrapRelaySettingsOrDefault(relaySettings);
+ return fn(settings);
+ },
+ [relaySettings],
+ );
+}
+
+export function useRelaySettingsUpdater() {
+ const { updateRelaySettings } = useAppContext();
+ const modifyRelaySettings = useRelaySettingsModifier();
+
+ return useCallback(
+ async (fn: UpdateFunction) => {
+ const modifiedSettings = modifyRelaySettings(fn);
+ await updateRelaySettings({ normal: modifiedSettings });
+ },
+ [updateRelaySettings, modifyRelaySettings],
+ );
}
diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts
index 51c1d67c0d..6977be4375 100644
--- a/gui/src/shared/daemon-rpc-types.ts
+++ b/gui/src/shared/daemon-rpc-types.ts
@@ -112,6 +112,14 @@ export type LiftedConstraint<T> = 'any' | T;
export function liftConstraint<T>(constraint: Constraint<T>): LiftedConstraint<T> {
return constraint === 'any' ? constraint : constraint.only;
}
+export function wrapConstraint<T>(
+ constraint: LiftedConstraint<T> | undefined | null,
+): Constraint<T> {
+ if (constraint) {
+ return constraint === 'any' ? 'any' : { only: constraint };
+ }
+ return 'any';
+}
export type ProxyType = 'shadowsocks' | 'custom';
export function proxyTypeToString(proxy: ProxyType): string {
@@ -267,19 +275,6 @@ export type RelaySettings =
customTunnelEndpoint: IRelaySettingsCustom;
};
-// types describing the partial update of RelaySettings
-export type RelaySettingsNormalUpdate = Partial<
- IRelaySettingsNormal<Partial<IOpenVpnConstraints>, Partial<IWireguardConstraints>>
->;
-
-export type RelaySettingsUpdate =
- | {
- normal: RelaySettingsNormalUpdate;
- }
- | {
- customTunnelEndpoint: IRelaySettingsCustom;
- };
-
export interface IRelayListWithEndpointData {
relayList: IRelayList;
wireguardEndpointData: IWireguardEndpointData;
diff --git a/gui/src/shared/ipc-schema.ts b/gui/src/shared/ipc-schema.ts
index 946b4fa99a..7981250c88 100644
--- a/gui/src/shared/ipc-schema.ts
+++ b/gui/src/shared/ipc-schema.ts
@@ -19,7 +19,7 @@ import {
IRelayListWithEndpointData,
ISettings,
ObfuscationSettings,
- RelaySettingsUpdate,
+ RelaySettings,
TunnelState,
VoucherResponse,
} from './daemon-rpc-types';
@@ -172,7 +172,7 @@ export const ipcSchema = {
setOpenVpnMssfix: invoke<number | undefined, void>(),
setWireguardMtu: invoke<number | undefined, void>(),
setWireguardQuantumResistant: invoke<boolean | undefined, void>(),
- updateRelaySettings: invoke<RelaySettingsUpdate, void>(),
+ updateRelaySettings: invoke<RelaySettings, void>(),
updateBridgeSettings: invoke<BridgeSettings, void>(),
setDnsOptions: invoke<IDnsOptions, void>(),
setObfuscationSettings: invoke<ObfuscationSettings, void>(),
diff --git a/gui/src/shared/relay-settings-builder.ts b/gui/src/shared/relay-settings-builder.ts
deleted file mode 100644
index e4c11e5132..0000000000
--- a/gui/src/shared/relay-settings-builder.ts
+++ /dev/null
@@ -1,189 +0,0 @@
-import {
- Constraint,
- IOpenVpnConstraints,
- IpVersion,
- IWireguardConstraints,
- RelayLocation,
- RelayProtocol,
- RelaySettingsNormalUpdate,
- RelaySettingsUpdate,
- TunnelProtocol,
-} from './daemon-rpc-types';
-import makeLocationBuilder, { ILocationBuilder } from './relay-location-builder';
-
-interface IExactOrAny<T, Self> {
- exact(value: T): Self;
- any(): Self;
-}
-
-interface IOpenVPNConfigurator {
- port: IExactOrAny<number, IOpenVPNConfigurator>;
- protocol: IExactOrAny<RelayProtocol, IOpenVPNConfigurator>;
-}
-
-interface IWireguardConfigurator {
- port: IExactOrAny<number, IWireguardConfigurator>;
- ipVersion: IExactOrAny<IpVersion, IWireguardConfigurator>;
- useMultihop: (value: boolean) => IWireguardConfigurator;
- entryLocation: IExactOrAny<RelayLocation, IWireguardConfigurator>;
-}
-
-interface ITunnelProtocolConfigurator {
- tunnelProtocol: IExactOrAny<TunnelProtocol, ITunnelProtocolConfigurator>;
-}
-
-interface ITunnelBuilder {
- openvpn(
- configurator: (openVpnConfigurator: IOpenVPNConfigurator) => void,
- ): NormalRelaySettingsBuilder;
- wireguard(
- configurator: (wireguardConfigurator: IWireguardConfigurator) => void,
- ): NormalRelaySettingsBuilder;
- tunnelProtocol(
- configurator: (tunnelProtocolConfigurator: ITunnelProtocolConfigurator) => void,
- ): NormalRelaySettingsBuilder;
-}
-
-class NormalRelaySettingsBuilder {
- private payload: RelaySettingsNormalUpdate = {};
-
- public build(): RelaySettingsUpdate {
- return {
- normal: this.payload,
- };
- }
-
- get location(): ILocationBuilder<NormalRelaySettingsBuilder> {
- return makeLocationBuilder(this, (location) => {
- this.payload.location = location;
- });
- }
-
- get tunnel(): ITunnelBuilder {
- const updateOpenvpn = (next: Partial<IOpenVpnConstraints>) => {
- if (this.payload.openvpnConstraints === undefined) {
- this.payload.openvpnConstraints = next;
- } else {
- const prev = this.payload.openvpnConstraints;
- this.payload.openvpnConstraints = {
- ...prev,
- ...next,
- };
- }
- };
-
- 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?: Constraint<TunnelProtocol>) => {
- this.payload.tunnelProtocol = next;
- };
-
- return {
- openvpn: (configurator: (configurator: IOpenVPNConfigurator) => void) => {
- const openvpnBuilder: IOpenVPNConfigurator = {
- get port() {
- const apply = (port: Constraint<number>) => {
- updateOpenvpn({ port });
- return this;
- };
- return {
- exact: (value: number) => apply({ only: value }),
- any: () => apply('any'),
- };
- },
- get protocol() {
- const apply = (protocol: Constraint<RelayProtocol>) => {
- updateOpenvpn({ protocol });
- return this;
- };
- return {
- exact: (value: RelayProtocol) => apply({ only: value }),
- any: () => apply('any'),
- };
- },
- };
-
- configurator(openvpnBuilder);
-
- return this;
- },
-
- wireguard: (configurator: (configurator: IWireguardConfigurator) => void) => {
- const wireguardBuilder: IWireguardConfigurator = {
- get port() {
- const apply = (port: Constraint<number>) => {
- updateWireguard({ port });
- return this;
- };
- return {
- exact: (value: number) => apply({ only: value }),
- any: () => apply('any'),
- };
- },
- get ipVersion() {
- const apply = (ipVersion: Constraint<IpVersion>) => {
- updateWireguard({ ipVersion });
- return this;
- };
- return {
- exact: (value: IpVersion) => apply({ only: value }),
- any: () => apply('any'),
- };
- },
- get useMultihop() {
- return (useMultihop: boolean) => {
- updateWireguard({ useMultihop });
- return this;
- };
- },
- get entryLocation() {
- const apply = (entryLocation: Constraint<RelayLocation> | undefined) => {
- updateWireguard({ entryLocation });
- return this;
- };
- return {
- exact: (entryLocation: RelayLocation) => apply({ only: entryLocation }),
- 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;
- },
- };
- }
-}
-
-export default {
- normal: () => new NormalRelaySettingsBuilder(),
-};