diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2021-01-26 09:19:06 +0100 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2021-01-26 09:19:06 +0100 |
| commit | 2c5163b9fa05e8b21ed92f6992e3a216e96817fe (patch) | |
| tree | 32f4f2e706e152626b31ca472e1e564f71340319 /gui/src/main | |
| parent | 2b055cc39c4eee4b8af8bb193143ddd4055b39ac (diff) | |
| parent | 5e9d51d61ecf3a7f8df10fcfc767213a108274c1 (diff) | |
| download | mullvadvpn-2c5163b9fa05e8b21ed92f6992e3a216e96817fe.tar.xz mullvadvpn-2c5163b9fa05e8b21ed92f6992e3a216e96817fe.zip | |
Merge branch 'sandbox-electron-renderer'
Diffstat (limited to 'gui/src/main')
| -rw-r--r-- | gui/src/main/index.ts | 54 | ||||
| -rw-r--r-- | gui/src/main/ipc-event-channel.ts | 5 | ||||
| -rw-r--r-- | gui/src/main/linux-desktop-entry.ts | 16 | ||||
| -rw-r--r-- | gui/src/main/load-translations.ts | 72 | ||||
| -rw-r--r-- | gui/src/main/logging.ts | 2 | ||||
| -rw-r--r-- | gui/src/main/window-controller.ts | 7 |
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; |
