summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-01-15 17:29:09 +0100
committerOskar Nyberg <oskar@mullvad.net>2021-07-02 16:15:01 +0200
commitb30ac8edef0d20beb1e770bbaea90de073020710 (patch)
tree2e7a05407955d6d67d7e65034a09d33759267ed4 /gui/src
parentf77cde89c6b8d3d580ee773628f89211a24852c5 (diff)
downloadmullvadvpn-b30ac8edef0d20beb1e770bbaea90de073020710.tar.xz
mullvadvpn-b30ac8edef0d20beb1e770bbaea90de073020710.zip
Add IPC and RPC methods and connect to Windows split tunneling functions
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/main/daemon-rpc.ts12
-rw-r--r--gui/src/main/gui-settings.ts2
-rw-r--r--gui/src/main/index.ts102
-rw-r--r--gui/src/renderer/app.tsx4
-rw-r--r--gui/src/shared/daemon-rpc-types.ts2
-rw-r--r--gui/src/shared/ipc-schema.ts18
6 files changed, 125 insertions, 15 deletions
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts
index c740393e2a..fabab8ecaf 100644
--- a/gui/src/main/daemon-rpc.ts
+++ b/gui/src/main/daemon-rpc.ts
@@ -476,6 +476,18 @@ export class DaemonRpc {
return response.toObject();
}
+ public async addSplitTunnelingApplication(path: string): Promise<void> {
+ await this.callString(this.client.addSplitTunnelApp, path);
+ }
+
+ public async removeSplitTunnelingApplication(path: string): Promise<void> {
+ await this.callString(this.client.removeSplitTunnelApp, path);
+ }
+
+ public async setSplitTunnelingState(enabled: boolean): Promise<void> {
+ await this.callBool(this.client.setSplitTunnelState, enabled);
+ }
+
private subscriptionId(): number {
const current = this.nextSubscriptionId;
this.nextSubscriptionId += 1;
diff --git a/gui/src/main/gui-settings.ts b/gui/src/main/gui-settings.ts
index 7708facc84..57dc754cd8 100644
--- a/gui/src/main/gui-settings.ts
+++ b/gui/src/main/gui-settings.ts
@@ -81,7 +81,7 @@ export default class GuiSettings {
return this.stateValue.unpinnedWindow;
}
- public addBrowsedForSplitTunnelingapplications(newApp: string) {
+ public addBrowsedForSplitTunnelingApplications(newApp: string) {
this.changeStateAndNotify({
...this.stateValue,
browsedForSplitTunnelingApplications: [...this.browsedForSplitTunnelingApplications, newApp],
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index 1785794818..6700db0a5c 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -16,6 +16,7 @@ import { sprintf } from 'sprintf-js';
import * as uuid from 'uuid';
import config from '../config.json';
import { hasExpired } from '../shared/account-expiry';
+import { IApplication } from '../shared/application-types';
import BridgeSettingsBuilder from '../shared/bridge-settings-builder';
import {
AccountToken,
@@ -75,8 +76,9 @@ import TrayIconController, { TrayIconType } from './tray-icon-controller';
import WindowController from './window-controller';
import { ITranslations } from '../shared/ipc-schema';
-// Only import when running app on Linux.
+// Only import split tunneling library on correct OS.
const linuxSplitTunneling = process.platform === 'linux' && require('./linux-split-tunneling');
+const windowsSplitTunneling = process.platform === 'win32' && require('./windows-split-tunneling');
const DAEMON_RPC_PATH =
process.platform === 'win32' ? 'unix:////./pipe/Mullvad VPN' : 'unix:///var/run/mullvad-vpn';
@@ -108,6 +110,10 @@ class ApplicationMain {
private tray?: Tray;
private trayIconController?: TrayIconController;
+ // True while file pickers are displayed which is used to decide if the Browser window should be
+ // hidden when losing focus.
+ private browsingFiles = false;
+
private daemonRpc = new DaemonRpc(DAEMON_RPC_PATH);
private daemonEventListener?: SubscriptionListener<DaemonEvent>;
private reconnectBackoff = new ReconnectionBackoff();
@@ -123,6 +129,8 @@ class ApplicationMain {
autoConnect: false,
blockWhenDisconnected: false,
showBetaReleases: false,
+ splitTunnel: false,
+ splitTunnelAppsList: [],
relaySettings: {
normal: {
location: 'any',
@@ -218,6 +226,8 @@ class ApplicationMain {
private rendererLog?: Logger;
private translations: ITranslations = { locale: this.locale };
+ private windowsSplitTunnelingApplications?: IApplication[];
+
public run() {
// Remove window animations to combat window flickering when opening window. Can be removed when
// this issue has been resolved: https://github.com/electron/electron/issues/12130
@@ -754,6 +764,10 @@ class ApplicationMain {
if (this.windowController) {
IpcMainEventChannel.settings.notify(this.windowController.webContents, newSettings);
+
+ if (windowsSplitTunneling) {
+ consumePromise(this.updateSplitTunnelingApplications(newSettings.splitTunnelAppsList));
+ }
}
// since settings can have the relay constraints changed, the relay
@@ -761,6 +775,20 @@ class ApplicationMain {
this.setRelays(this.relays, newSettings.relaySettings, newSettings.bridgeState);
}
+ private async updateSplitTunnelingApplications(appList: string[]): Promise<void> {
+ const { applications } = await windowsSplitTunneling.getApplications({
+ applicationPaths: appList,
+ });
+ this.windowsSplitTunnelingApplications = applications;
+
+ if (this.windowController) {
+ IpcMainEventChannel.windowsSplitTunneling.notify(
+ this.windowController.webContents,
+ applications,
+ );
+ }
+ }
+
private setLocation(newLocation: ILocation) {
this.location = newLocation;
@@ -1056,6 +1084,7 @@ class ApplicationMain {
translations: this.translations,
platform: process.platform,
runningInDevelopment: process.env.NODE_ENV === 'development',
+ windowsSplitTunnelingApplications: this.windowsSplitTunnelingApplications,
}));
IpcMainEventChannel.settings.handleSetAllowLan((allowLan: boolean) =>
@@ -1155,18 +1184,63 @@ class ApplicationMain {
});
IpcMainEventChannel.wireguardKeys.handleVerifyKey(() => this.daemonRpc.verifyWireguardKey());
- IpcMainEventChannel.splitTunneling.handleGetApplications(() => {
+ IpcMainEventChannel.linuxSplitTunneling.handleGetApplications(() => {
if (linuxSplitTunneling) {
return linuxSplitTunneling.getApplications(this.locale);
} else {
- throw Error('linuxSplitTunneling called without being imported');
+ throw Error('linuxSplitTunneling.getApplications function called without being imported');
}
});
- IpcMainEventChannel.splitTunneling.handleLaunchApplication((application) => {
+ IpcMainEventChannel.windowsSplitTunneling.handleGetApplications((updateCache: boolean) => {
+ if (windowsSplitTunneling) {
+ return windowsSplitTunneling.getApplications({
+ updateCache,
+ });
+ } else {
+ throw Error('windowsSplitTunneling.getApplications function called without being imported');
+ }
+ });
+ IpcMainEventChannel.linuxSplitTunneling.handleLaunchApplication((application) => {
if (linuxSplitTunneling) {
return linuxSplitTunneling.launchApplication(application);
} else {
- throw Error('linuxSplitTunneling called without being imported');
+ throw Error('linuxSplitTunneling.launchApplication function called without being imported');
+ }
+ });
+
+ IpcMainEventChannel.windowsSplitTunneling.handleSetState((enabled) => {
+ if (windowsSplitTunneling) {
+ return this.daemonRpc.setSplitTunnelingState(enabled);
+ } else {
+ throw Error('windowsSplitTunneling.setState function called without being imported');
+ }
+ });
+ IpcMainEventChannel.windowsSplitTunneling.handleAddApplication(async (application) => {
+ if (windowsSplitTunneling) {
+ // If the applications is a string (path) it's an application picked with the file picker
+ // that we want to add to the list of additional applications.
+ if (typeof application === 'string') {
+ this.guiSettings.addBrowsedForSplitTunnelingApplications(application);
+ const applicationPath = windowsSplitTunneling.addApplicationPathToCache(application);
+ await this.daemonRpc.addSplitTunnelingApplication(applicationPath);
+ } else {
+ await this.daemonRpc.addSplitTunnelingApplication(application.absolutepath);
+ }
+ } else {
+ throw Error(
+ 'windowsSplitTunneling.handleAddApplication function called without being imported',
+ );
+ }
+ });
+ IpcMainEventChannel.windowsSplitTunneling.handleRemoveApplication((application) => {
+ if (windowsSplitTunneling) {
+ return this.daemonRpc.removeSplitTunnelingApplication(
+ typeof application === 'string' ? application : application.absolutepath,
+ );
+ } else {
+ throw Error(
+ 'windowsSplitTunneling.handleRemoveApplication function called without being imported',
+ );
}
});
@@ -1228,7 +1302,21 @@ class ApplicationMain {
await shell.openExternal(url);
}
});
- IpcMainEventChannel.app.handleShowOpenDialog((options) => dialog.showOpenDialog(options));
+ IpcMainEventChannel.app.handleShowOpenDialog(async (options) => {
+ this.browsingFiles = true;
+ const response = await dialog.showOpenDialog({
+ defaultPath: app.getPath('home'),
+ ...options,
+ });
+ this.browsingFiles = false;
+ return response;
+ });
+
+ if (windowsSplitTunneling) {
+ this.guiSettings.browsedForSplitTunnelingApplications.forEach(
+ windowsSplitTunneling.addApplicationPathToCache,
+ );
+ }
}
private async createNewAccount(): Promise<string> {
@@ -1806,7 +1894,7 @@ class ApplicationMain {
cursorPos.y >= trayBounds.y &&
cursorPos.x <= trayBounds.x + trayBounds.width &&
cursorPos.y <= trayBounds.y + trayBounds.height;
- if (!isCursorInside) {
+ if (!isCursorInside && !this.browsingFiles) {
windowController.hide();
}
});
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index 36e49c7c77..7cb8e538b0 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -449,13 +449,13 @@ export default class AppRenderer {
}
public getSplitTunnelingApplications() {
- return IpcRendererEventChannel.splitTunneling.getApplications();
+ return IpcRendererEventChannel.linuxSplitTunneling.getApplications();
}
public launchExcludedApplication(
application: ILinuxSplitTunnelingApplication | string,
): Promise<LaunchApplicationResult> {
- return IpcRendererEventChannel.splitTunneling.launchApplication(application);
+ return IpcRendererEventChannel.linuxSplitTunneling.launchApplication(application);
}
public collectProblemReport(toRedact?: string): Promise<string> {
diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts
index b0319369cf..95285ef884 100644
--- a/gui/src/shared/daemon-rpc-types.ts
+++ b/gui/src/shared/daemon-rpc-types.ts
@@ -311,6 +311,8 @@ export interface ISettings {
tunnelOptions: ITunnelOptions;
bridgeSettings: BridgeSettings;
bridgeState: BridgeState;
+ splitTunnel: boolean;
+ splitTunnelAppsList: string[];
}
export type KeygenEvent = INewWireguardKey | KeygenFailure;
diff --git a/gui/src/shared/ipc-schema.ts b/gui/src/shared/ipc-schema.ts
index 01c5c53a95..5789bcc149 100644
--- a/gui/src/shared/ipc-schema.ts
+++ b/gui/src/shared/ipc-schema.ts
@@ -1,5 +1,5 @@
import { GetTextTranslations } from 'gettext-parser';
-import { ILinuxSplitTunnelingApplication } from './application-types';
+import { IApplication, ILinuxSplitTunnelingApplication } from './application-types';
import {
AccountToken,
BridgeSettings,
@@ -56,6 +56,7 @@ export interface IAppStateSnapshot {
translations: ITranslations;
platform: NodeJS.Platform;
runningInDevelopment: boolean;
+ windowsSplitTunnelingApplications?: IApplication[];
}
// The different types of requests are:
@@ -178,10 +179,6 @@ export const ipcSchema = {
generateKey: invoke<void, KeygenEvent>(),
verifyKey: invoke<void, boolean>(),
},
- splitTunneling: {
- getApplications: invoke<void, ILinuxSplitTunnelingApplication[]>(),
- launchApplication: invoke<ILinuxSplitTunnelingApplication | string, LaunchApplicationResult>(),
- },
problemReport: {
collectLogs: invoke<string | undefined, string>(),
sendReport: invoke<{ email: string; message: string; savedReportId: string }, void>(),
@@ -190,4 +187,15 @@ export const ipcSchema = {
logging: {
log: send<ILogEntry>(),
},
+ linuxSplitTunneling: {
+ getApplications: invoke<void, ILinuxSplitTunnelingApplication[]>(),
+ launchApplication: invoke<ILinuxSplitTunnelingApplication | string, LaunchApplicationResult>(),
+ },
+ windowsSplitTunneling: {
+ '': notifyRenderer<IApplication[]>(),
+ setState: invoke<boolean, void>(),
+ getApplications: invoke<boolean, { fromCache: boolean; applications: IApplication[] }>(),
+ addApplication: invoke<IApplication | string, void>(),
+ removeApplication: invoke<IApplication | string, void>(),
+ },
};