From df52521c171bb6d159d863513253751e35586d63 Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Fri, 26 Jan 2018 14:53:51 -0500 Subject: [PATCH] MEW-01-009 & MEW-01-010: Electron security fixes (#910) * Handle opening of external links in electron. Minor refactor of window code. * Convert updates from in-app modal to electron dialogs. Remove in-app code and preload bridge. * Refine new window blocking. Re-enable tsconfig to look at electron-app. * Clean up shared * Whoops, wrong protocol format --- .../components/Header/components/Version.scss | 61 ------- .../components/Header/components/Version.tsx | 46 +----- common/components/UpdateModal.scss | 62 ------- common/components/UpdateModal.tsx | 142 ---------------- common/components/ui/NewTabLink.tsx | 9 +- common/utils/electron.ts | 25 --- electron-app/main/index.ts | 72 +-------- electron-app/main/updater.ts | 151 ++++++++++++------ electron-app/main/window.ts | 78 +++++++++ electron-app/preload.ts | 19 --- jest_config/jest.config.json | 3 +- jest_config/jest.int.config.json | 3 +- shared/electronBridge.ts | 9 -- shared/electronEvents.ts | 12 -- tsconfig.json | 2 +- webpack_config/webpack.electron-dev.js | 3 +- 16 files changed, 188 insertions(+), 509 deletions(-) delete mode 100644 common/components/Header/components/Version.scss delete mode 100644 common/components/UpdateModal.scss delete mode 100644 common/components/UpdateModal.tsx delete mode 100644 common/utils/electron.ts create mode 100644 electron-app/main/window.ts delete mode 100644 electron-app/preload.ts delete mode 100644 shared/electronBridge.ts delete mode 100644 shared/electronEvents.ts diff --git a/common/components/Header/components/Version.scss b/common/components/Header/components/Version.scss deleted file mode 100644 index 03a64a76..00000000 --- a/common/components/Header/components/Version.scss +++ /dev/null @@ -1,61 +0,0 @@ -@import 'common/sass/variables'; - -@keyframes new-update-popin { - 0% { - opacity: 0; - transform: scale(0.7); - } - 60% { - opacity: 1; - transform: scale(1.2); - } - 100% { - opacity: 1; - transform: scale(1); - } -} - -@keyframes new-update-glow { - 0% { - opacity: 1; - transform: scale(1); - }, - 80%, 100% { - opacity: 0; - transform: scale(2.5); - } -} - -.Version { - position: relative; - - &-text { - &.has-update:hover { - cursor: pointer; - text-decoration: underline; - } - } - - &-new { - position: absolute; - top: 0px; - left: -12px; - width: 8px; - height: 8px; - border-radius: 100%; - background: $brand-warning; - animation: new-update-popin 500ms ease 1; - - &:before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - border-radius: 100%; - box-shadow: 0 0 3px $brand-warning; - animation: new-update-glow 1200ms ease infinite; - } - } -} diff --git a/common/components/Header/components/Version.tsx b/common/components/Header/components/Version.tsx index ea6c92c7..f50feba8 100644 --- a/common/components/Header/components/Version.tsx +++ b/common/components/Header/components/Version.tsx @@ -1,48 +1,6 @@ import React from 'react'; import { VERSION } from 'config/data'; -import UpdateModal, { UpdateInfo } from 'components/UpdateModal'; -import { addListener } from 'utils/electron'; -import EVENTS from 'shared/electronEvents'; -import './Version.scss'; -interface State { - updateInfo: UpdateInfo | null; - isModalOpen: boolean; -} +const Version: React.SFC<{}> = () =>
v{VERSION}
; -export default class Version extends React.Component<{}, State> { - public state: State = { - updateInfo: null, - isModalOpen: false - }; - - public componentDidMount() { - addListener(EVENTS.UPDATE.UPDATE_AVAILABLE, updateInfo => { - this.setState({ updateInfo }); - }); - } - - public render() { - const { updateInfo, isModalOpen } = this.state; - return ( -
- - v{VERSION} - - {updateInfo && ( - - - - - )} -
- ); - } - - private openModal = () => this.setState({ isModalOpen: true }); - private closeModal = () => this.setState({ isModalOpen: false }); -} +export default Version; diff --git a/common/components/UpdateModal.scss b/common/components/UpdateModal.scss deleted file mode 100644 index c4eb8f16..00000000 --- a/common/components/UpdateModal.scss +++ /dev/null @@ -1,62 +0,0 @@ -@import 'common/sass/variables'; - -.UpdateModal { - cursor: default; - @media (min-width: 680px) { - min-width: 680px; - } - - &-title { - margin-top: 0; - margin-bottom: $space-xs; - } - - &-date { - font-size: $font-size-small; - color: $gray; - padding-bottom: $space-sm; - border-bottom: 1px solid $gray-lighter; - } - - &-downloader { - padding: 50px 30px 80px; - text-align: center; - - &-bar { - position: relative; - margin: 0 20px; - height: 16px; - border-radius: 4px; - background: $gray-lighter; - margin-bottom: $space-sm; - - &-inner { - position: absolute; - top: 0; - left: 0; - bottom: 0; - border-radius: 4px; - background: $brand-primary; - transition: width 100ms ease; - } - } - - &-info { - color: $gray-light; - font-size: $font-size-xs; - - &-bit { - &:after { - display: inline-block; - content: "•"; - padding: 0 $space-xs; - opacity: 0.8; - } - - &:last-child:after { - display: none; - } - } - } - } -} diff --git a/common/components/UpdateModal.tsx b/common/components/UpdateModal.tsx deleted file mode 100644 index d5855b91..00000000 --- a/common/components/UpdateModal.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import moment from 'moment'; -import { showNotification, TShowNotification } from 'actions/notifications'; -import { Spinner, NewTabLink } from 'components/ui'; -import Modal, { IButton } from 'components/ui/Modal'; -import { addListener, sendEvent } from 'utils/electron'; -import EVENTS from 'shared/electronEvents'; -import { bytesToHuman } from 'utils/formatters'; -import './UpdateModal.scss'; - -export interface UpdateInfo { - version: string; - sha512: string; - releaseDate: string; - releaseName: string; - releaseNotes: string; -} - -export interface DownloadProgress { - bytesPerSecond: number; - percent: number; - transferred: number; - total: number; -} - -interface Props { - isOpen: boolean; - updateInfo: UpdateInfo; - showNotification: TShowNotification; - handleClose(): void; -} - -interface State { - isDownloading: boolean; - downloadProgress: DownloadProgress | null; -} - -class UpdateModal extends React.Component { - public state: State = { - isDownloading: false, - downloadProgress: null - }; - - public componentDidMount() { - addListener(EVENTS.UPDATE.UPDATE_DOWNLOADED, () => { - sendEvent(EVENTS.UPDATE.QUIT_AND_INSTALL); - }); - addListener(EVENTS.UPDATE.DOWNLOAD_PROGRESS, downloadProgress => { - this.setState({ downloadProgress }); - }); - addListener(EVENTS.UPDATE.ERROR, err => { - console.error('Update failed:', err); - this.setState({ isDownloading: false }); - this.props.showNotification( - 'danger', - - Update could not be downloaded, please visit{' '} - - our github - {' '} - to download the latest release - , - Infinity - ); - }); - } - - public render() { - const { isOpen, updateInfo, handleClose } = this.props; - const { isDownloading, downloadProgress } = this.state; - const buttons: IButton[] | undefined = downloadProgress - ? undefined - : [ - { - text: {isDownloading && } Download Update, - type: 'primary', - onClick: this.downloadUpdate, - disabled: isDownloading - }, - { - text: 'Close', - type: 'default', - onClick: handleClose - } - ]; - - return ( - -
- {downloadProgress ? ( -
-

Downloading...

-
-
-
-
- - Downloaded {downloadProgress.percent.toFixed(1)}% - - - {bytesToHuman(downloadProgress.bytesPerSecond)}/s - - - Total Size {bytesToHuman(downloadProgress.total)} - -
-
- ) : ( -
-

{updateInfo.releaseName}

-
{moment(updateInfo.releaseDate).format('LL')}
-
-
- )} -
- - ); - } - - private downloadUpdate = () => { - this.setState({ isDownloading: true }); - sendEvent('UPDATE:download-update'); - }; -} - -export default connect(undefined, { showNotification })(UpdateModal); diff --git a/common/components/ui/NewTabLink.tsx b/common/components/ui/NewTabLink.tsx index 95fb67dd..f011aaa6 100644 --- a/common/components/ui/NewTabLink.tsx +++ b/common/components/ui/NewTabLink.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { openInBrowser } from 'utils/electron'; interface AAttributes { charset?: string; @@ -40,17 +39,11 @@ export class NewTabLink extends React.Component { public render() { const { content, children, ...rest } = this.props; return ( - + {content || children} ); } - - private handleClick(ev: React.MouseEvent) { - if (openInBrowser(ev.currentTarget.href)) { - ev.preventDefault(); - } - } } export default NewTabLink; diff --git a/common/utils/electron.ts b/common/utils/electron.ts deleted file mode 100644 index 0e09b0c2..00000000 --- a/common/utils/electron.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Handles integrations with Electron. Wherever possible, should stub out -// behavior with noop's if not in the Electron environment, to simplify code. -import { ElectronBridgeFunctions } from 'shared/electronBridge'; -const bridge: ElectronBridgeFunctions | null = (window as any).electronBridge; - -export const addListener: ElectronBridgeFunctions['addListener'] = (event, cb) => { - if (bridge && bridge.addListener) { - // @ts-ignore unused ev - bridge.addListener(event, (ev, data) => cb(data)); - } -}; - -export const sendEvent: ElectronBridgeFunctions['sendEvent'] = (event, data) => { - if (bridge && bridge.sendEvent) { - bridge.sendEvent(event, data); - } -}; - -export const openInBrowser: ElectronBridgeFunctions['openInBrowser'] = url => { - if (bridge && bridge.openInBrowser) { - bridge.openInBrowser(url); - return true; - } - return false; -}; diff --git a/electron-app/main/index.ts b/electron-app/main/index.ts index 6be98398..c0234a3b 100644 --- a/electron-app/main/index.ts +++ b/electron-app/main/index.ts @@ -1,63 +1,5 @@ -import { app, BrowserWindow, Menu } from 'electron'; -import * as path from 'path'; -import updater from './updater'; -import MENU from './menu'; - -const isDevelopment = process.env.NODE_ENV !== 'production'; - -// Global reference to mainWindow -// Necessary to prevent window from being garbage collected -let mainWindow; - -function createMainWindow() { - // Construct new BrowserWindow - const window = new BrowserWindow({ - title: 'MyEtherWallet', - backgroundColor: '#fbfbfb', - width: 1220, - height: 800, - minWidth: 320, - minHeight: 400, - // TODO - Implement styles for custom title bar in components/ui/TitleBar.scss - // frame: false, - // titleBarStyle: 'hidden', - webPreferences: { - devTools: true, - nodeIntegration: false, - preload: path.resolve(__dirname, 'preload.js') - } - }); - - const url = isDevelopment - ? `http://localhost:${process.env.HTTPS ? 3443 : 3000}` - : `file://${__dirname}/index.html`; - window.loadURL(url); - - window.on('closed', () => { - mainWindow = null; - }); - - window.webContents.on('devtools-opened', () => { - window.focus(); - setImmediate(() => { - window.focus(); - }); - }); - - if (isDevelopment) { - window.webContents.on('did-fail-load', () => { - setTimeout(() => { - if (window && window.webContents) { - window.webContents.reload(); - } - }, 500); - }); - } - - Menu.setApplicationMenu(Menu.buildFromTemplate(MENU)); - - return window; -} +import { app } from 'electron'; +import getWindow from './window'; // Quit application when all windows are closed app.on('window-all-closed', () => { @@ -71,16 +13,10 @@ app.on('window-all-closed', () => { app.on('activate', () => { // On macOS it is common to re-create a window // even after all windows have been closed - if (mainWindow === null) { - mainWindow = createMainWindow(); - updater(app, mainWindow); - } + getWindow(); }); // Create main BrowserWindow when electron is ready app.on('ready', () => { - mainWindow = createMainWindow(); - mainWindow.webContents.on('did-finish-load', () => { - updater(app, mainWindow); - }); + getWindow(); }); diff --git a/electron-app/main/updater.ts b/electron-app/main/updater.ts index 1f0d09bb..c08c264c 100644 --- a/electron-app/main/updater.ts +++ b/electron-app/main/updater.ts @@ -1,97 +1,144 @@ -import { App, BrowserWindow, ipcMain } from 'electron'; -import { autoUpdater } from 'electron-updater'; -import EVENTS from '../../shared/electronEvents'; +import { app, dialog, BrowserWindow } from 'electron'; +import { autoUpdater, UpdateInfo } from 'electron-updater'; import TEST_RELEASE from './testrelease.json'; autoUpdater.autoDownload = false; +// Set to 'true' if you want to test update behavior. Requires a recompile. +const shouldMockUpdate = false && process.env.NODE_ENV !== 'production'; +const shouldMockUpdateError = false && process.env.NODE_ENV !== 'production'; +let hasRunUpdater = false; +let hasStartedUpdating = false; + enum AutoUpdaterEvents { CHECKING_FOR_UPDATE = 'checking-for-update', - UPDATE_NOT_AVAILABLE = 'update-not-available', UPDATE_AVAILABLE = 'update-available', DOWNLOAD_PROGRESS = 'download-progress', UPDATE_DOWNLOADED = 'update-downloaded', ERROR = 'error' } -export default (app: App, window: BrowserWindow) => { - // Set to 'true' if you want to test update behavior. Requires a recompile. - const shouldMockUpdate = true && process.env.NODE_ENV !== 'production'; +export default function(mainWindow: BrowserWindow) { + if (hasRunUpdater) { + return; + } + hasRunUpdater = true; - // Report update status - autoUpdater.on(AutoUpdaterEvents.CHECKING_FOR_UPDATE, () => { - window.webContents.send(EVENTS.UPDATE.CHECKING_FOR_UPDATE); - }); - - autoUpdater.on(AutoUpdaterEvents.UPDATE_NOT_AVAILABLE, () => { - window.webContents.send(EVENTS.UPDATE.UPDATE_NOT_AVAILABLE); - }); - - autoUpdater.on(AutoUpdaterEvents.UPDATE_AVAILABLE, info => { - window.webContents.send(EVENTS.UPDATE.UPDATE_AVAILABLE, info); + autoUpdater.on(AutoUpdaterEvents.UPDATE_AVAILABLE, (info: UpdateInfo) => { + dialog.showMessageBox( + { + type: 'question', + buttons: ['Yes, start downloading', 'Maybe later'], + title: `An Update is Available (v${info.version})`, + message: `An Update is Available (v${info.version})`, + detail: + 'A new version has been released. Would you like to start downloading the update? You will be notified when the download is finished.' + }, + response => { + if (response === 0) { + if (shouldMockUpdate) { + mockDownload(); + } else { + autoUpdater.downloadUpdate(); + } + } + } + ); + hasStartedUpdating = true; }); autoUpdater.on(AutoUpdaterEvents.DOWNLOAD_PROGRESS, progress => { - window.webContents.send(EVENTS.UPDATE.DOWNLOAD_PROGRESS, progress); + mainWindow.setTitle(`MyEtherWallet (Downloading update... ${Math.round(progress.percent)}%)`); + mainWindow.setProgressBar(progress.percent / 100); }); autoUpdater.on(AutoUpdaterEvents.UPDATE_DOWNLOADED, () => { - window.webContents.send(EVENTS.UPDATE.UPDATE_DOWNLOADED); + resetWindowFromUpdates(mainWindow); + dialog.showMessageBox( + { + type: 'question', + buttons: ['Yes, restart now', 'Maybe later'], + title: 'Update Has Been Downloaded', + message: 'Download complete!', + detail: + 'The new version of MyEtherWallet has finished downloading. Would you like to restart to complete the installation?' + }, + response => { + if (response === 0) { + if (shouldMockUpdate) { + app.quit(); + } else { + autoUpdater.quitAndInstall(); + } + } + } + ); }); - autoUpdater.on(AutoUpdaterEvents.ERROR, (err, msg) => { + autoUpdater.on(AutoUpdaterEvents.ERROR, (err: Error) => { console.error('Update failed with an error'); console.error(err); - window.webContents.send(EVENTS.UPDATE.ERROR, msg); + + // If they haven't started updating yet, just fail silently + if (!hasStartedUpdating) { + return; + } + + resetWindowFromUpdates(mainWindow); + dialog.showErrorBox( + 'Downloading Update has Failed', + `The update could not be downloaded. Restart the app and try again later, or manually install the new update at https://github.com/MyEtherWallet/MyEtherWallet/releases\n\n(${ + err.name + }: ${err.message})` + ); }); + // Kick off the check autoUpdater.checkForUpdatesAndNotify(); - // Listen for restart request - ipcMain.on(EVENTS.UPDATE.DOWNLOAD_UPDATE, () => { - if (shouldMockUpdate) { - mockDownload(window); - } else { - autoUpdater.downloadUpdate(); - } - }); - - ipcMain.on(EVENTS.UPDATE.QUIT_AND_INSTALL, () => { - if (shouldMockUpdate) { - app.quit(); - } else { - autoUpdater.quitAndInstall(); - } - }); - // Simulate a test release if (shouldMockUpdate) { - mockUpdateCheck(window); + mockUpdateCheck(); } -}; +} + +function resetWindowFromUpdates(window: BrowserWindow) { + window.setTitle('MyEtherWallet'); + window.setProgressBar(-1); // Clears progress bar +} // Mock functions for dev testing -function mockUpdateCheck(window: BrowserWindow) { - window.webContents.send(EVENTS.UPDATE.CHECKING_FOR_UPDATE); +function mockUpdateCheck() { + autoUpdater.emit(AutoUpdaterEvents.CHECKING_FOR_UPDATE); setTimeout(() => { - window.webContents.send(EVENTS.UPDATE.UPDATE_AVAILABLE, TEST_RELEASE); + autoUpdater.emit(AutoUpdaterEvents.UPDATE_AVAILABLE, TEST_RELEASE); }, 3000); } -function mockDownload(window: BrowserWindow) { - for (let i = 0; i < 101; i++) { +function mockDownload() { + for (let i = 0; i < 11; i++) { setTimeout(() => { + if (i >= 5 && shouldMockUpdateError) { + if (i === 5) { + autoUpdater.emit( + AutoUpdaterEvents.ERROR, + new Error('Test error, nothing actually failed') + ); + } + return; + } + const total = 150000000; - window.webContents.send(EVENTS.UPDATE.DOWNLOAD_PROGRESS, { - bytesPerSecond: Math.round(Math.random() * 100000), - percent: i, + autoUpdater.emit(AutoUpdaterEvents.DOWNLOAD_PROGRESS, { + bytesPerSecond: Math.round(Math.random() * 100000000), + percent: i * 10, transferred: total / i, total }); - if (i === 100) { - window.webContents.send(EVENTS.UPDATE.UPDATE_DOWNLOADED); + if (i === 10) { + autoUpdater.emit(AutoUpdaterEvents.UPDATE_DOWNLOADED); } - }, 50 * i); + }, 500 * i); } } diff --git a/electron-app/main/window.ts b/electron-app/main/window.ts new file mode 100644 index 00000000..bcca6b0f --- /dev/null +++ b/electron-app/main/window.ts @@ -0,0 +1,78 @@ +import { BrowserWindow, Menu, shell } from 'electron'; +import { URL } from 'url'; +import MENU from './menu'; +import updater from './updater'; +const isDevelopment = process.env.NODE_ENV !== 'production'; + +// Cached reference, preventing recreations +let window; + +// Construct new BrowserWindow +export default function getWindow() { + if (window) { + return window; + } + + window = new BrowserWindow({ + title: 'MyEtherWallet', + backgroundColor: '#fbfbfb', + width: 1220, + height: 800, + minWidth: 320, + minHeight: 400, + // TODO - Implement styles for custom title bar in components/ui/TitleBar.scss + // frame: false, + // titleBarStyle: 'hidden', + webPreferences: { + devTools: true, + nodeIntegration: false, + contextIsolation: true + } + }); + + const port = process.env.HTTPS ? '3443' : '3000'; + const appUrl = isDevelopment ? `http://localhost:${port}` : `file://${__dirname}/index.html`; + window.loadURL(appUrl); + + window.on('closed', () => { + window = null; + }); + + window.webContents.on('new-window', (ev, urlStr) => { + // Kill all new window requests by default + ev.preventDefault(); + + // Only allow HTTPS urls to actually be opened + const url = new URL(urlStr); + if (url.protocol === 'https:') { + shell.openExternal(urlStr); + } else { + console.warn(`Blocked request to open new window '${urlStr}', only HTTPS links are allowed`); + } + }); + + window.webContents.on('did-finish-load', () => { + updater(window); + }); + + window.webContents.on('devtools-opened', () => { + window.focus(); + setImmediate(() => { + window.focus(); + }); + }); + + if (isDevelopment) { + window.webContents.on('did-fail-load', () => { + setTimeout(() => { + if (window && window.webContents) { + window.webContents.reload(); + } + }, 500); + }); + } + + Menu.setApplicationMenu(Menu.buildFromTemplate(MENU)); + + return window; +} diff --git a/electron-app/preload.ts b/electron-app/preload.ts deleted file mode 100644 index da9fd22c..00000000 --- a/electron-app/preload.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Selectively expose node integration, since all node integrations are -// disabled by default for security purposes. -import { ipcRenderer, shell } from 'electron'; -import { ElectronBridgeFunctions } from '../shared/electronBridge'; -const win = window as any; - -const functions: ElectronBridgeFunctions = { - addListener(event, cb) { - ipcRenderer.on(event, cb); - }, - sendEvent(event, data) { - ipcRenderer.send(event, data); - }, - openInBrowser(url) { - return shell.openExternal(url); - } -}; - -win.electronBridge = functions; diff --git a/jest_config/jest.config.json b/jest_config/jest.config.json index 91ddb83f..b93875a1 100644 --- a/jest_config/jest.config.json +++ b/jest_config/jest.config.json @@ -10,8 +10,7 @@ "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/jest_config/__mocks__/fileMock.ts", "\\.(css|scss|less)$": "/jest_config/__mocks__/styleMock.ts", - "\\.worker.ts":"/jest_config/__mocks__/workerMock.js", - "^shared(.*)$": "/shared$1" + "\\.worker.ts":"/jest_config/__mocks__/workerMock.js" }, "testPathIgnorePatterns": ["/common/config"], "setupFiles": [ diff --git a/jest_config/jest.int.config.json b/jest_config/jest.int.config.json index f2be1359..404dce04 100644 --- a/jest_config/jest.int.config.json +++ b/jest_config/jest.int.config.json @@ -9,8 +9,7 @@ "moduleNameMapper": { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/jest_config/__mocks__/fileMock.ts", - "\\.(css|scss|less)$": "/jest_config/__mocks__/styleMock.ts", - "^shared(.*)$": "/shared$1" + "\\.(css|scss|less)$": "/jest_config/__mocks__/styleMock.ts" }, "testPathIgnorePatterns": ["/common/config"], "setupFiles": [ diff --git a/shared/electronBridge.ts b/shared/electronBridge.ts deleted file mode 100644 index f24582f4..00000000 --- a/shared/electronBridge.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Provide typescript definitions / mappings between `electron-app/preload.ts` -// and 'common/utils/electron.ts' -export type ElectronBridgeCallback = (data?: any) => void; - -export interface ElectronBridgeFunctions { - addListener(event: string, cb: ElectronBridgeCallback); - sendEvent(event: string, data?: any); - openInBrowser(url: string): boolean; -} diff --git a/shared/electronEvents.ts b/shared/electronEvents.ts deleted file mode 100644 index 60fb2fd6..00000000 --- a/shared/electronEvents.ts +++ /dev/null @@ -1,12 +0,0 @@ -export default { - UPDATE: { - CHECKING_FOR_UPDATE: 'UPDATE:checking-for-update', - UPDATE_NOT_AVAILABLE: 'UPDATE:update-not-available', - UPDATE_AVAILABLE: 'UPDATE:update-available', - DOWNLOAD_PROGRESS: 'UPDATE:download-progress', - UPDATE_DOWNLOADED: 'UPDATE:update-downloaded', - ERROR: 'UPDATE:error', - DOWNLOAD_UPDATE: 'UPDATE:download-update', - QUIT_AND_INSTALL: 'UPDATE:quit-and-install' - } -}; diff --git a/tsconfig.json b/tsconfig.json index 8f948409..0547c07f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,7 +23,7 @@ }, "include": [ "./common/", - "./electron/", + "./electron-app/", "spec", "./node_modules/types-rlp/index.d.ts" ], diff --git a/webpack_config/webpack.electron-dev.js b/webpack_config/webpack.electron-dev.js index ff1a4525..bf96ef29 100644 --- a/webpack_config/webpack.electron-dev.js +++ b/webpack_config/webpack.electron-dev.js @@ -8,8 +8,7 @@ const makeConfig = require('./makeConfig'); const electronConfig = { target: 'electron-main', entry: { - main: path.join(config.path.electron, 'main/index.ts'), - preload: path.join(config.path.electron, 'preload.ts') + main: path.join(config.path.electron, 'main/index.ts') }, module: { rules: [config.typescriptRule]