diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2021-01-15 17:29:09 +0100 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2021-07-02 16:15:01 +0200 |
| commit | b30ac8edef0d20beb1e770bbaea90de073020710 (patch) | |
| tree | 2e7a05407955d6d67d7e65034a09d33759267ed4 /gui/src | |
| parent | f77cde89c6b8d3d580ee773628f89211a24852c5 (diff) | |
| download | mullvadvpn-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.ts | 12 | ||||
| -rw-r--r-- | gui/src/main/gui-settings.ts | 2 | ||||
| -rw-r--r-- | gui/src/main/index.ts | 102 | ||||
| -rw-r--r-- | gui/src/renderer/app.tsx | 4 | ||||
| -rw-r--r-- | gui/src/shared/daemon-rpc-types.ts | 2 | ||||
| -rw-r--r-- | gui/src/shared/ipc-schema.ts | 18 |
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>(), + }, }; |
