summaryrefslogtreecommitdiffhomepage
path: root/gui/src/main
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2024-04-11 18:11:33 +0200
committerOskar Nyberg <oskar@mullvad.net>2024-04-11 18:11:33 +0200
commit9aaebecc3c6d1838722a66875b5a330ca7967020 (patch)
treec877bcc16c9eb3e325aecdd5f2861b9e6f5824a5 /gui/src/main
parentd2e198cd8ce15225d4329cbb61f4561e293ea239 (diff)
parent36322705705857c549fa90616884bc64740cbbef (diff)
downloadmullvadvpn-9aaebecc3c6d1838722a66875b5a330ca7967020.tar.xz
mullvadvpn-9aaebecc3c6d1838722a66875b5a330ca7967020.zip
Merge branch 'add-custom-bridge-to-gui-des-431'
Diffstat (limited to 'gui/src/main')
-rw-r--r--gui/src/main/daemon-rpc.ts187
-rw-r--r--gui/src/main/settings.ts13
2 files changed, 73 insertions, 127 deletions
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts
index 703ad027cc..531ec80ced 100644
--- a/gui/src/main/daemon-rpc.ts
+++ b/gui/src/main/daemon-rpc.ts
@@ -17,6 +17,7 @@ import {
ApiAccessMethodSettings,
AuthFailedError,
BridgeSettings,
+ BridgesMethod,
BridgeState,
BridgeType,
ConnectionConfig,
@@ -27,6 +28,7 @@ import {
DaemonEvent,
DeviceEvent,
DeviceState,
+ DirectMethod,
EndpointObfuscationType,
ErrorState,
ErrorStateCause,
@@ -82,7 +84,6 @@ const NETWORK_CALL_TIMEOUT = 10000;
const CHANNEL_STATE_TIMEOUT = 1000 * 60 * 60;
const noConnectionError = new Error('No connection established to daemon');
-const configNotSupported = new Error('Setting custom settings is not supported');
const invalidErrorStateCause = new Error(
'VPN_PERMISSION_DENIED is not a valid error state cause on desktop',
);
@@ -347,51 +348,17 @@ export class DaemonRpc {
public async setBridgeSettings(bridgeSettings: BridgeSettings): Promise<void> {
const grpcBridgeSettings = new grpcTypes.BridgeSettings();
- if (bridgeSettings.type === 'custom') {
- throw configNotSupported;
- }
-
- grpcBridgeSettings.setBridgeType(grpcTypes.BridgeSettings.BridgeType.NORMAL);
+ grpcBridgeSettings.setBridgeType(
+ bridgeSettings.type === 'normal'
+ ? grpcTypes.BridgeSettings.BridgeType.NORMAL
+ : grpcTypes.BridgeSettings.BridgeType.CUSTOM,
+ );
const normalSettings = convertToNormalBridgeSettings(bridgeSettings.normal);
grpcBridgeSettings.setNormal(normalSettings);
if (bridgeSettings.custom) {
- const customProxy = new grpcTypes.CustomProxy();
-
- const customSettings = bridgeSettings.custom;
-
- if ('local' in customSettings) {
- const local = customSettings.local;
- const socks5Local = new grpcTypes.Socks5Local();
- socks5Local.setLocalPort(local.localPort);
- socks5Local.setRemoteIp(local.remoteIp);
- socks5Local.setRemotePort(local.remotePort);
- customProxy.setSocks5local(socks5Local);
- }
- if ('remote' in customSettings) {
- const remote = customSettings.remote;
- const socks5Remote = new grpcTypes.Socks5Remote();
- if (remote.auth) {
- const auth = new grpcTypes.SocksAuth();
- auth.setUsername(remote.auth.username);
- auth.setPassword(remote.auth.password);
- socks5Remote.setAuth(auth);
- }
- socks5Remote.setIp(remote.ip);
- socks5Remote.setPort(remote.port);
- customProxy.setSocks5remote(socks5Remote);
- }
- if ('shadowsocks' in customSettings) {
- const shadowsocks = customSettings.shadowsocks;
- const shadowOut = new grpcTypes.Shadowsocks();
- shadowOut.setCipher(shadowsocks.cipher);
- shadowOut.setIp(shadowsocks.ip);
- shadowOut.setPort(shadowsocks.port);
- shadowOut.setPassword(shadowsocks.password);
- customProxy.setShadowsocks(shadowOut);
- }
-
+ const customProxy = convertToCustomProxy(bridgeSettings.custom);
grpcBridgeSettings.setCustom(customProxy);
}
@@ -1276,41 +1243,8 @@ function convertFromBridgeSettings(bridgeSettings: grpcTypes.BridgeSettings): Br
ownership,
};
- let custom = undefined;
-
- if (bridgeSettingsObject.custom) {
- const localSettings = bridgeSettingsObject.custom.socks5local;
- if (localSettings) {
- custom = {
- local: {
- localPort: localSettings.localPort,
- remoteIp: localSettings.remoteIp,
- remotePort: localSettings.remotePort,
- },
- };
- }
- const remoteSettings = bridgeSettingsObject.custom.socks5remote;
- if (remoteSettings) {
- custom = {
- remote: {
- ip: remoteSettings.ip,
- port: remoteSettings.port,
- auth: remoteSettings.auth && { ...remoteSettings.auth },
- },
- };
- }
- const shadowsocksSettings = bridgeSettingsObject.custom.shadowsocks;
- if (shadowsocksSettings) {
- custom = {
- shadowsocks: {
- ip: shadowsocksSettings.ip,
- port: shadowsocksSettings.port,
- password: shadowsocksSettings.password,
- cipher: shadowsocksSettings.cipher,
- },
- };
- }
- }
+ const grpcCustom = bridgeSettings.getCustom();
+ const custom = grpcCustom ? convertFromCustomProxy(grpcCustom) : undefined;
return { type, normal, custom };
}
@@ -1910,15 +1844,16 @@ function convertFromApiAccessMethodSettings(
): ApiAccessMethodSettings {
const direct = convertFromApiAccessMethodSetting(
ensureExists(accessMethods.getDirect(), "no 'Direct' access method was found"),
- );
+ ) as AccessMethodSetting<DirectMethod>;
const bridges = convertFromApiAccessMethodSetting(
ensureExists(accessMethods.getMullvadBridges(), "no 'Mullvad Bridges' access method was found"),
- );
- const custom =
- accessMethods
- .getCustomList()
- .filter((setting) => setting.hasId() && setting.hasAccessMethod())
- .map(convertFromApiAccessMethodSetting) ?? [];
+ ) as AccessMethodSetting<BridgesMethod>;
+ const custom = accessMethods
+ .getCustomList()
+ .filter((setting) => setting.hasId() && setting.hasAccessMethod())
+ .map(convertFromApiAccessMethodSetting)
+ // The last filter helps TypeScript infer the custom proxy type.
+ .filter(isCustomProxy);
return {
direct,
@@ -1927,6 +1862,12 @@ function convertFromApiAccessMethodSettings(
};
}
+function isCustomProxy(
+ accessMethod: AccessMethodSetting,
+): accessMethod is AccessMethodSetting<CustomProxy> {
+ return accessMethod.type !== 'direct' && accessMethod.type !== 'bridges';
+}
+
function convertFromApiAccessMethodSetting(
setting: grpcTypes.AccessMethodSetting,
): AccessMethodSetting {
@@ -1948,52 +1889,52 @@ function convertFromAccessMethod(method: grpcTypes.AccessMethod): AccessMethod {
case grpcTypes.AccessMethod.AccessMethodCase.BRIDGES:
return { type: 'bridges' };
case grpcTypes.AccessMethod.AccessMethodCase.CUSTOM: {
- const proxy = method.getCustom()!;
- switch (proxy.getProxyMethodCase()) {
- case grpcTypes.CustomProxy.ProxyMethodCase.SOCKS5LOCAL: {
- const socks5Local = proxy.getSocks5local()!;
- return {
- type: 'socks5-local',
- remoteIp: socks5Local.getRemoteIp(),
- remotePort: socks5Local.getRemotePort(),
- remoteTransportProtocol: convertFromTransportProtocol(
- socks5Local.getRemoteTransportProtocol(),
- ),
- localPort: socks5Local.getLocalPort(),
- };
- }
- case grpcTypes.CustomProxy.ProxyMethodCase.SOCKS5REMOTE: {
- const socks5Remote = proxy.getSocks5remote()!;
- const auth = socks5Remote.getAuth();
- return {
- type: 'socks5-remote',
- ip: socks5Remote.getIp(),
- port: socks5Remote.getPort(),
- authentication: auth === undefined ? undefined : convertFromSocksAuth(auth),
- };
- }
- case grpcTypes.CustomProxy.ProxyMethodCase.SHADOWSOCKS: {
- const shadowsocks = proxy.getShadowsocks()!;
- return {
- type: 'shadowsocks',
- ip: shadowsocks.getIp(),
- port: shadowsocks.getPort(),
- password: shadowsocks.getPassword(),
- cipher: shadowsocks.getCipher(),
- };
- }
- case grpcTypes.CustomProxy.ProxyMethodCase.PROXY_METHOD_NOT_SET:
- throw new Error('Custom method not set, which should always be set');
- }
- // This break is required to prevent eslint from complainting about fallthrough, even though
- // all cases are covered above.
- break;
+ return convertFromCustomProxy(method.getCustom()!);
}
case grpcTypes.AccessMethod.AccessMethodCase.ACCESS_METHOD_NOT_SET:
throw new Error('Access method not set, which should always be set');
}
}
+function convertFromCustomProxy(proxy: grpcTypes.CustomProxy): CustomProxy {
+ switch (proxy.getProxyMethodCase()) {
+ case grpcTypes.CustomProxy.ProxyMethodCase.SOCKS5LOCAL: {
+ const socks5Local = proxy.getSocks5local()!;
+ return {
+ type: 'socks5-local',
+ remoteIp: socks5Local.getRemoteIp(),
+ remotePort: socks5Local.getRemotePort(),
+ remoteTransportProtocol: convertFromTransportProtocol(
+ socks5Local.getRemoteTransportProtocol(),
+ ),
+ localPort: socks5Local.getLocalPort(),
+ };
+ }
+ case grpcTypes.CustomProxy.ProxyMethodCase.SOCKS5REMOTE: {
+ const socks5Remote = proxy.getSocks5remote()!;
+ const auth = socks5Remote.getAuth();
+ return {
+ type: 'socks5-remote',
+ ip: socks5Remote.getIp(),
+ port: socks5Remote.getPort(),
+ authentication: auth === undefined ? undefined : convertFromSocksAuth(auth),
+ };
+ }
+ case grpcTypes.CustomProxy.ProxyMethodCase.SHADOWSOCKS: {
+ const shadowsocks = proxy.getShadowsocks()!;
+ return {
+ type: 'shadowsocks',
+ ip: shadowsocks.getIp(),
+ port: shadowsocks.getPort(),
+ password: shadowsocks.getPassword(),
+ cipher: shadowsocks.getCipher(),
+ };
+ }
+ case grpcTypes.CustomProxy.ProxyMethodCase.PROXY_METHOD_NOT_SET:
+ throw new Error('Custom method not set, which should always be set');
+ }
+}
+
function convertFromSocksAuth(auth: grpcTypes.SocksAuth): SocksAuth {
return {
username: auth.getUsername(),
diff --git a/gui/src/main/settings.ts b/gui/src/main/settings.ts
index 16996eebd9..8bf60d9108 100644
--- a/gui/src/main/settings.ts
+++ b/gui/src/main/settings.ts
@@ -1,6 +1,5 @@
import fs from 'fs/promises';
-import BridgeSettingsBuilder from '../shared/bridge-settings-builder';
import { ISettings } from '../shared/daemon-rpc-types';
import { ICurrentAppVersionInfo } from '../shared/ipc-types';
import log from '../shared/logging';
@@ -44,9 +43,15 @@ export default class Settings implements Readonly<ISettings> {
IpcMainEventChannel.settings.handleSetBridgeState(async (bridgeState) => {
await this.daemonRpc.setBridgeState(bridgeState);
- // Reset bridge constraints to `any` when the state is set to auto or off
- if (bridgeState === 'auto' || bridgeState === 'off') {
- await this.daemonRpc.setBridgeSettings(new BridgeSettingsBuilder().location.any().build());
+ // Reset bridge constraints to `any` when the state is set to auto or off if not custom
+ if (
+ (bridgeState === 'auto' || bridgeState === 'off') &&
+ this.bridgeSettings.type === 'normal'
+ ) {
+ await this.daemonRpc.setBridgeSettings({
+ ...this.bridgeSettings,
+ normal: { ...this.bridgeSettings.normal, location: 'any' },
+ });
}
});
IpcMainEventChannel.settings.handleSetOpenVpnMssfix((mssfix?: number) =>