diff --git a/package.json b/package.json index 86e4695eac7..eb83012fc25 100644 --- a/package.json +++ b/package.json @@ -113,10 +113,11 @@ "@angular/upgrade": "5.2.0", "angular2-toaster": "4.0.2", "angulartics2": "5.0.1", - "core-js": "^2.4.1", + "core-js": "2.4.1", "desktop-idle": "1.1.1", - "keytar": "^4.1.0", - "rxjs": "^5.5.6", - "zone.js": "^0.8.19" + "electron-updater": "2.20.1", + "keytar": "4.1.0", + "rxjs": "5.5.6", + "zone.js": "0.8.19" } } diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 39b6beadcc0..31ef15e009a 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -750,5 +750,24 @@ }, "disableFaviconDesc": { "message": "Website Icons provide a recognizable image next to each login item in your vault." + }, + "about": { + "message": "About" + }, + "copy": { + "message": "Copy", + "description": "Copy to clipboard" + }, + "checkForUpdates": { + "message": "Check For Updates" + }, + "version": { + "message": "Version $VERSION_NUM$", + "placeholders": { + "version_num": { + "content": "$1", + "example": "1.2.3" + } + } } } diff --git a/src/main.ts b/src/main.ts index fc959e2bf0e..60efc842a28 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,6 +3,7 @@ import { BrowserWindow } from 'electron'; import { MenuMain } from './main/menu.main'; import { MessagingMain } from './main/messaging.main'; import { PowerMonitorMain } from './main/powerMonitor.main'; +import { UpdaterMain } from './main/updater.main'; import { WindowMain } from './main/window.main'; import { DesktopMainMessagingService } from './services/desktopMainMessaging.service'; @@ -25,7 +26,8 @@ const i18nService = new I18nService('en', './locales/'); const storageService = new DesktopStorageService(); const messagingService = new DesktopMainMessagingService(windowMain, messagingMain); -const menuMain = new MenuMain(windowMain, i18nService, messagingService); +const updaterMain = new UpdaterMain(); +const menuMain = new MenuMain(windowMain, updaterMain, i18nService, messagingService); const powerMonitorMain = new PowerMonitorMain(storageService, messagingService); windowMain.init().then(() => { @@ -34,6 +36,7 @@ windowMain.init().then(() => { }).then(() => { menuMain.init(); powerMonitorMain.init(); + updaterMain.init(); }, (e: any) => { // tslint:disable-next-line console.log(e); diff --git a/src/main/menu.main.ts b/src/main/menu.main.ts index dd0f45ed77c..aae48aff7bc 100644 --- a/src/main/menu.main.ts +++ b/src/main/menu.main.ts @@ -1,6 +1,7 @@ import { app, BrowserWindow, + clipboard, dialog, ipcMain, Menu, @@ -8,14 +9,15 @@ import { shell, } from 'electron'; +import { UpdaterMain } from './updater.main'; import { WindowMain } from './window.main'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { MessagingService } from 'jslib/abstractions/messaging.service'; export class MenuMain { - constructor(private windowMain: WindowMain, private i18nService: I18nService, - private messagingService: MessagingService) { } + constructor(private windowMain: WindowMain, private updaterMain: UpdaterMain, + private i18nService: I18nService, private messagingService: MessagingService) { } init() { const template: MenuItemConstructorOptions[] = [ @@ -306,6 +308,10 @@ export class MenuMain { if (process.platform === 'darwin') { const firstMenuPart: MenuItemConstructorOptions[] = [ { role: 'about' }, + { + label: this.i18nService.t('checkForUpdates'), + click: () => this.updaterMain.checkForUpdate(), + }, ]; template.unshift({ @@ -331,8 +337,40 @@ export class MenuMain { { role: 'front' }, ]; } else { + // File menu template[0].submenu = (template[0].submenu as MenuItemConstructorOptions[]).concat( firstMenuOptions); + + // About menu + template[template.length - 1].submenu = + (template[template.length - 1].submenu as MenuItemConstructorOptions[]).concat([ + { type: 'separator' }, + { + label: this.i18nService.t('checkForUpdates'), + click: () => this.updaterMain.checkForUpdate(), + }, + { + label: this.i18nService.t('about'), + click: () => { + const aboutInformation = this.i18nService.t('version', app.getVersion()) + + '\nShell ' + process.versions['electron'] + + '\nRenderer ' + process.versions['chrome'] + + '\nNode ' + process.versions['node'] + + '\nArchitecture ' + process.arch; + const result = dialog.showMessageBox(this.windowMain.win, { + title: 'Bitwarden', + message: 'Bitwarden', + detail: aboutInformation, + type: 'info', + noLink: true, + buttons: [this.i18nService.t('ok'), this.i18nService.t('copy')], + }); + if (result === 1) { + clipboard.writeText(aboutInformation); + } + }, + } + ]); } const menu = Menu.buildFromTemplate(template); diff --git a/src/main/updater.main.ts b/src/main/updater.main.ts new file mode 100644 index 00000000000..4ea51e2f502 --- /dev/null +++ b/src/main/updater.main.ts @@ -0,0 +1,15 @@ +import { autoUpdater } from "electron-updater" + +const UpdaterCheckInitalDelay = 5 * 1000; // 5 seconds +const UpdaterCheckInterval = 12 * 60 * 60 * 1000; // 12 hours + +export class UpdaterMain { + async init() { + global.setTimeout(async () => await this.checkForUpdate(), UpdaterCheckInitalDelay); + global.setInterval(async () => await this.checkForUpdate(), UpdaterCheckInterval); + } + + async checkForUpdate() { + return await autoUpdater.checkForUpdatesAndNotify(); + } +}