summaryrefslogtreecommitdiffhomepage
path: root/gui/src/main
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-01-26 09:19:06 +0100
committerOskar Nyberg <oskar@mullvad.net>2021-01-26 09:19:06 +0100
commit2c5163b9fa05e8b21ed92f6992e3a216e96817fe (patch)
tree32f4f2e706e152626b31ca472e1e564f71340319 /gui/src/main
parent2b055cc39c4eee4b8af8bb193143ddd4055b39ac (diff)
parent5e9d51d61ecf3a7f8df10fcfc767213a108274c1 (diff)
downloadmullvadvpn-2c5163b9fa05e8b21ed92f6992e3a216e96817fe.tar.xz
mullvadvpn-2c5163b9fa05e8b21ed92f6992e3a216e96817fe.zip
Merge branch 'sandbox-electron-renderer'
Diffstat (limited to 'gui/src/main')
-rw-r--r--gui/src/main/index.ts54
-rw-r--r--gui/src/main/ipc-event-channel.ts5
-rw-r--r--gui/src/main/linux-desktop-entry.ts16
-rw-r--r--gui/src/main/load-translations.ts72
-rw-r--r--gui/src/main/logging.ts2
-rw-r--r--gui/src/main/window-controller.ts7
6 files changed, 125 insertions, 31 deletions
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index cbd56f3843..f3ac7e72c0 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -34,11 +34,12 @@ import {
RelaySettingsUpdate,
TunnelState,
} from '../shared/daemon-rpc-types';
-import { loadTranslations, messages } from '../shared/gettext';
+import { messages, relayLocations } from '../shared/gettext';
import { SYSTEM_PREFERRED_LOCALE_KEY } from '../shared/gui-settings-state';
-import { IpcMainEventChannel } from '../shared/ipc-event-channel';
import log, { ConsoleOutput, Logger } from '../shared/logging';
import { LogLevel } from '../shared/logging-types';
+import { IpcMainEventChannel } from './ipc-event-channel';
+import { ICurrentAppVersionInfo } from '../shared/ipc-types';
import {
AccountExpiredNotificationProvider,
CloseToAccountExpiryNotificationProvider,
@@ -65,11 +66,13 @@ import {
IpcInput,
OLD_LOG_FILES,
} from './logging';
+import { loadTranslations } from './load-translations';
import NotificationController from './notification-controller';
import { resolveBin } from './proc';
import ReconnectionBackoff from './reconnection-backoff';
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.
const linuxSplitTunneling = process.platform === 'linux' && require('./linux-split-tunneling');
@@ -88,13 +91,6 @@ enum AppQuitStage {
ready,
}
-export interface ICurrentAppVersionInfo {
- gui: string;
- daemon: string;
- isConsistent: boolean;
- isBeta: boolean;
-}
-
type AccountVerification = { status: 'verified' } | { status: 'deferred'; error: Error };
class ApplicationMain {
@@ -204,6 +200,7 @@ class ApplicationMain {
private autoConnectFallbackScheduler = new Scheduler();
private rendererLog?: Logger;
+ private translations: ITranslations = { locale: this.locale };
public run() {
// Remove window animations to combat window flickering when opening window. Can be removed when
@@ -212,6 +209,10 @@ class ApplicationMain {
app.commandLine.appendSwitch('wm-window-animations-disabled');
}
+ if (process.platform !== 'linux') {
+ app.enableSandbox();
+ }
+
this.overrideAppPaths();
if (this.ensureSingleInstance()) {
@@ -373,7 +374,7 @@ class ApplicationMain {
this.blockRequests();
- this.updateCurrentLocale();
+ this.translations = this.updateCurrentLocale();
this.daemonRpc.addConnectionObserver(
new ConnectionObserver(this.onDaemonConnected, this.onDaemonDisconnected),
@@ -1007,6 +1008,9 @@ class ApplicationMain {
upgradeVersion: this.upgradeVersion,
guiSettings: this.guiSettings.state,
wireguardPublicKey: this.wireguardPublicKey,
+ translations: this.translations,
+ platform: process.platform,
+ runningInDevelopment: process.env.NODE_ENV === 'development',
}));
IpcMainEventChannel.settings.handleSetAllowLan((allowLan: boolean) =>
@@ -1074,7 +1078,7 @@ class ApplicationMain {
IpcMainEventChannel.guiSettings.handleSetPreferredLocale((locale: string) => {
this.guiSettings.preferredLocale = locale;
- this.didChangeLocale();
+ return Promise.resolve(this.updateCurrentLocale());
});
IpcMainEventChannel.account.handleCreate(() => this.createNewAccount());
@@ -1368,15 +1372,13 @@ class ApplicationMain {
log.info(`Detected locale: ${this.locale}`);
- loadTranslations(this.locale, messages);
- }
-
- private didChangeLocale() {
- this.updateCurrentLocale();
-
- if (this.windowController) {
- IpcMainEventChannel.locale.notify(this.windowController.webContents, this.locale);
- }
+ const messagesTranslations = loadTranslations(this.locale, messages);
+ const relayLocationsTranslations = loadTranslations(this.locale, relayLocations);
+ return {
+ locale: this.locale,
+ messages: messagesTranslations,
+ relayLocations: relayLocationsTranslations,
+ };
}
// Since the app frontend never performs any network requests, all requests originating from the
@@ -1446,11 +1448,15 @@ class ApplicationMain {
transparent: !this.guiSettings.unpinnedWindow,
useContentSize: true,
webPreferences: {
- nodeIntegration: true,
- devTools: process.env.NODE_ENV === 'development',
- // TODO: Remove use of remote
- enableRemoteModule: true,
+ preload: path.join(__dirname, '../renderer/preloadBundle.js'),
+ nodeIntegration: false,
+ nodeIntegrationInWorker: false,
+ nodeIntegrationInSubFrames: false,
+ enableRemoteModule: false,
+ sandbox: process.platform !== 'linux',
+ contextIsolation: true,
spellcheck: false,
+ devTools: process.env.NODE_ENV === 'development',
},
};
diff --git a/gui/src/main/ipc-event-channel.ts b/gui/src/main/ipc-event-channel.ts
new file mode 100644
index 0000000000..9bd8af1490
--- /dev/null
+++ b/gui/src/main/ipc-event-channel.ts
@@ -0,0 +1,5 @@
+import { ipcMain } from 'electron';
+import { createIpcMain } from '../shared/ipc-helpers';
+import { ipcSchema } from '../shared/ipc-schema';
+
+export const IpcMainEventChannel = createIpcMain(ipcSchema, ipcMain);
diff --git a/gui/src/main/linux-desktop-entry.ts b/gui/src/main/linux-desktop-entry.ts
index dc1ae0e57b..a2712bb7e3 100644
--- a/gui/src/main/linux-desktop-entry.ts
+++ b/gui/src/main/linux-desktop-entry.ts
@@ -1,4 +1,5 @@
import child_process from 'child_process';
+import { nativeImage } from 'electron';
import fs from 'fs';
import path from 'path';
import { ILinuxApplication } from '../shared/application-types';
@@ -45,7 +46,7 @@ export async function getAppIcon(name?: string) {
// Chromium doesn't support .xpm files
const extensions = ['svg', 'png'];
- return findIcon(name, extensions, [
+ const iconPath = await findIcon(name, extensions, [
getIconDirectories(),
await getGtkThemeDirectories(),
// Begin with preferred sized but if nothing matches other sizes should be considered as well.
@@ -53,6 +54,19 @@ export async function getAppIcon(name?: string) {
// Search in all categories of icons.
[/.*/],
]);
+
+ if (iconPath && path.extname(iconPath) === '.svg') {
+ try {
+ const contents = await fs.promises.readFile(iconPath);
+ return `data:image/svg+xml;base64,${contents.toString('base64')}`;
+ } catch (error) {
+ log.error(`Failed to read icon of application: ${name},`, error);
+ }
+ } else if (iconPath) {
+ return nativeImage.createFromPath(iconPath).toDataURL();
+ }
+
+ return undefined;
}
// Implemented according to freedesktop specification.
diff --git a/gui/src/main/load-translations.ts b/gui/src/main/load-translations.ts
new file mode 100644
index 0000000000..63d76f0ac6
--- /dev/null
+++ b/gui/src/main/load-translations.ts
@@ -0,0 +1,72 @@
+import fs from 'fs';
+import { GetTextTranslations, po } from 'gettext-parser';
+import Gettext from 'node-gettext';
+import path from 'path';
+import log from '../shared/logging';
+
+const SOURCE_LANGUAGE = 'en';
+const LOCALES_DIR = path.resolve(__dirname, '../../locales');
+
+export function loadTranslations(
+ currentLocale: string,
+ catalogue: Gettext,
+): GetTextTranslations | undefined {
+ // First look for exact match of the current locale
+ const preferredLocales = [];
+
+ if (currentLocale !== SOURCE_LANGUAGE) {
+ preferredLocales.push(currentLocale);
+ }
+
+ // In case of region bound locale like en-US, fallback to en.
+ const language = Gettext.getLanguageCode(currentLocale);
+ if (currentLocale !== language) {
+ preferredLocales.push(language);
+ }
+
+ const domain = catalogue.domain;
+ for (const locale of preferredLocales) {
+ const parsedTranslations = parseTranslation(locale, domain, catalogue);
+ if (parsedTranslations) {
+ log.info(`Loaded translations ${locale}/${domain}`);
+ catalogue.setLocale(locale);
+ return parsedTranslations;
+ }
+ }
+
+ // Reset the locale to source language if we couldn't load the catalogue for the requested locale
+ // Add empty translations to suppress some of the warnings produces by node-gettext
+ catalogue.addTranslations(SOURCE_LANGUAGE, domain, {});
+ catalogue.setLocale(SOURCE_LANGUAGE);
+ return;
+}
+
+function parseTranslation(
+ locale: string,
+ domain: string,
+ catalogue: Gettext,
+): GetTextTranslations | undefined {
+ const filename = path.join(LOCALES_DIR, locale, `${domain}.po`);
+ let contents: string;
+
+ try {
+ contents = fs.readFileSync(filename, { encoding: 'utf8' });
+ } catch (error) {
+ if (error.code !== 'ENOENT') {
+ log.error(`Cannot read the gettext file "${filename}": ${error.message}`);
+ }
+ return undefined;
+ }
+
+ let translations: GetTextTranslations;
+ try {
+ translations = po.parse(contents);
+ } catch (error) {
+ log.error(`Cannot parse the gettext file "${filename}": ${error.message}`);
+ return undefined;
+ }
+
+ catalogue.addTranslations(locale, domain, translations);
+
+ return translations;
+}
diff --git a/gui/src/main/logging.ts b/gui/src/main/logging.ts
index fb21c54b48..7029625d3f 100644
--- a/gui/src/main/logging.ts
+++ b/gui/src/main/logging.ts
@@ -1,7 +1,7 @@
import { app } from 'electron';
import fs from 'fs';
import path from 'path';
-import { IpcMainEventChannel } from '../shared/ipc-event-channel';
+import { IpcMainEventChannel } from './ipc-event-channel';
import { LogLevel, ILogInput, ILogOutput } from '../shared/logging-types';
export const OLD_LOG_FILES = ['frontend-renderer.log'];
diff --git a/gui/src/main/window-controller.ts b/gui/src/main/window-controller.ts
index a44724d23f..69ae6acb02 100644
--- a/gui/src/main/window-controller.ts
+++ b/gui/src/main/window-controller.ts
@@ -1,15 +1,12 @@
import { BrowserWindow, Display, screen, Tray, WebContents } from 'electron';
-import { IpcMainEventChannel } from '../shared/ipc-event-channel';
+import { IpcMainEventChannel } from './ipc-event-channel';
+import { IWindowShapeParameters } from '../shared/ipc-types';
interface IPosition {
x: number;
y: number;
}
-export interface IWindowShapeParameters {
- arrowPosition?: number;
-}
-
interface IWindowPositioning {
getPosition(window: BrowserWindow): IPosition;
getWindowShapeParameters(window: BrowserWindow): IWindowShapeParameters;