diff --git a/jslib b/jslib index 05e6d2c0f0..42bf9b2edb 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 05e6d2c0f0aa6cae6a5e53fac6dccf2a1d75a555 +Subproject commit 42bf9b2edbafcda5d180df6d2746f19881a63315 diff --git a/src/main.ts b/src/main.ts index 0b1ca7feab..0aeafdf1b5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,6 +11,7 @@ import { UpdaterMain } from './main/updater.main'; import { ConstantsService } from 'jslib/services/constants.service'; +import { KeytarStorageListener } from 'jslib/electron/keytarStorageListener'; import { ElectronLogService } from 'jslib/electron/services/electronLog.service'; import { ElectronStorageService } from 'jslib/electron/services/electronStorage.service'; import { WindowMain } from 'jslib/electron/window.main'; @@ -20,6 +21,7 @@ export class Main { i18nService: I18nService; storageService: ElectronStorageService; messagingService: DesktopMainMessagingService; + keytarStorageListener: KeytarStorageListener; windowMain: WindowMain; messagingMain: MessagingMain; @@ -61,9 +63,12 @@ export class Main { this.updaterMain = new UpdaterMain(this); this.menuMain = new MenuMain(this); this.powerMonitorMain = new PowerMonitorMain(this); + + this.keytarStorageListener = new KeytarStorageListener('Bitwarden'); } bootstrap() { + this.keytarStorageListener.init(); this.windowMain.init().then(async () => { const locale = await this.storageService.get(ConstantsService.localeKey); await this.i18nService.init(locale != null ? locale : app.getLocale()); diff --git a/src/main/menu.main.ts b/src/main/menu.main.ts index cc38186aef..9162ee3b24 100644 --- a/src/main/menu.main.ts +++ b/src/main/menu.main.ts @@ -12,11 +12,13 @@ import { import { Main } from '../main'; +import { BaseMenu } from 'jslib/electron/baseMenu'; + import { isMacAppStore, isSnapStore, isWindowsStore } from 'jslib/electron/utils'; import { ConstantsService } from 'jslib/services/constants.service'; -export class MenuMain { +export class MenuMain extends BaseMenu { menu: Menu; updateMenuItem: MenuItem; addNewLogin: MenuItem; @@ -35,9 +37,12 @@ export class MenuMain { searchVault: MenuItem; unlockedRequiredMenuItems: MenuItem[] = []; - constructor(private main: Main) { } + constructor(private main: Main) { + super(main.i18nService, main.windowMain, 'Bitwarden', () => this.main.messagingService.send('logout')); + } init() { + this.initProperties(); this.initContextMenu(); this.initApplicationMenu(); @@ -73,86 +78,6 @@ export class MenuMain { this.logOut.enabled = isAuthenticated; } - private initContextMenu() { - if (this.main.windowMain.win == null) { - return; - } - - const selectionMenu = Menu.buildFromTemplate([ - { - label: this.main.i18nService.t('copy'), - role: 'copy', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('selectAll'), - role: 'selectall', - }, - ]); - - const inputMenu = Menu.buildFromTemplate([ - { - label: this.main.i18nService.t('undo'), - role: 'undo', - }, - { - label: this.main.i18nService.t('redo'), - role: 'redo', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('cut'), - role: 'cut', - enabled: false, - }, - { - label: this.main.i18nService.t('copy'), - role: 'copy', - enabled: false, - }, - { - label: this.main.i18nService.t('paste'), - role: 'paste', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('selectAll'), - role: 'selectall', - }, - ]); - - const inputSelectionMenu = Menu.buildFromTemplate([ - { - label: this.main.i18nService.t('cut'), - role: 'cut', - }, - { - label: this.main.i18nService.t('copy'), - role: 'copy', - }, - { - label: this.main.i18nService.t('paste'), - role: 'paste', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('selectAll'), - role: 'selectall', - }, - ]); - - this.main.windowMain.win.webContents.on('context-menu', (e, props) => { - const selected = props.selectionText && props.selectionText.trim() !== ''; - if (props.isEditable && selected) { - inputSelectionMenu.popup(this.main.windowMain.win); - } else if (props.isEditable) { - inputMenu.popup(this.main.windowMain.win); - } else if (selected) { - selectionMenu.popup(this.main.windowMain.win); - } - }); - } - private initApplicationMenu() { const accountSubmenu: MenuItemConstructorOptions[] = [ { @@ -210,24 +135,7 @@ export class MenuMain { }, }, { type: 'separator' }, - { - label: this.main.i18nService.t('logOut'), - id: 'logOut', - click: () => { - const result = dialog.showMessageBox(this.main.windowMain.win, { - title: this.main.i18nService.t('logOut'), - message: this.main.i18nService.t('logOut'), - detail: this.main.i18nService.t('logOutConfirmation'), - buttons: [this.main.i18nService.t('logOut'), this.main.i18nService.t('cancel')], - cancelId: 1, - defaultId: 0, - noLink: true, - }); - if (result === 0) { - this.main.messagingService.send('logout'); - } - }, - }, + this.logOutMenuItemOptions, ]; if (!isMacAppStore() && !isWindowsStore()) { @@ -287,40 +195,10 @@ export class MenuMain { }, ], }, - { - label: this.main.i18nService.t('edit'), - submenu: [ - { - label: this.main.i18nService.t('undo'), - role: 'undo', - }, - { - label: this.main.i18nService.t('redo'), - role: 'redo', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('cut'), - role: 'cut', - }, - { - label: this.main.i18nService.t('copy'), - role: 'copy', - }, - { - label: this.main.i18nService.t('paste'), - role: 'paste', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('selectAll'), - role: 'selectall', - }, - ], - }, + this.editMenuItemOptions, { label: this.main.i18nService.t('view'), - submenu: [ + submenu: ([ { label: this.main.i18nService.t('searchVault'), id: 'searchVault', @@ -340,53 +218,13 @@ export class MenuMain { click: () => this.main.messagingService.send('openPasswordHistory'), }, { type: 'separator' }, - { - label: this.main.i18nService.t('zoomIn'), - role: 'zoomin', accelerator: 'CmdOrCtrl+=', - }, - { - label: this.main.i18nService.t('zoomOut'), - role: 'zoomout', accelerator: 'CmdOrCtrl+-', - }, - { - label: this.main.i18nService.t('resetZoom'), - role: 'resetzoom', accelerator: 'CmdOrCtrl+0', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('toggleFullScreen'), - role: 'togglefullscreen', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('reload'), - role: 'forcereload', - }, - { - label: this.main.i18nService.t('toggleDevTools'), - role: 'toggledevtools', - accelerator: 'F12', - }, - ], + ] as MenuItemConstructorOptions[]).concat(this.viewSubMenuItemOptions), }, { label: this.main.i18nService.t('account'), submenu: accountSubmenu, }, - { - label: this.main.i18nService.t('window'), - role: 'window', - submenu: [ - { - label: this.main.i18nService.t('minimize'), - role: 'minimize', - }, - { - label: this.main.i18nService.t('close'), - role: 'close', - }, - ], - }, + this.windowMenuItemOptions, { label: this.main.i18nService.t('help'), role: 'help', @@ -531,54 +369,14 @@ export class MenuMain { } template.unshift({ - label: 'Bitwarden', + label: this.appName, submenu: firstMenuPart.concat(firstMenuOptions, [ { type: 'separator' }, - { - label: this.main.i18nService.t('services'), - role: 'services', submenu: [], - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('hideBitwarden'), - role: 'hide', - }, - { - label: this.main.i18nService.t('hideOthers'), - role: 'hideothers', - }, - { - label: this.main.i18nService.t('showAll'), - role: 'unhide', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('quitBitwarden'), - role: 'quit', - }, - ]), + ], this.macAppMenuItemOptions), }); // Window menu - template[template.length - 2].submenu = [ - { - label: this.main.i18nService.t('close'), - role: isMacAppStore() ? 'quit' : 'close', - }, - { - label: this.main.i18nService.t('minimize'), - role: 'minimize', - }, - { - label: this.main.i18nService.t('zoom'), - role: 'zoom', - }, - { type: 'separator' }, - { - label: this.main.i18nService.t('bringAllToFront'), - role: 'front', - }, - ]; + template[template.length - 2].submenu = this.macWindowSubmenuOptions; } else { // File menu template[0].submenu = (template[0].submenu as MenuItemConstructorOptions[]).concat( @@ -593,27 +391,7 @@ export class MenuMain { aboutMenuAdditions.push(updateMenuItem); } - aboutMenuAdditions.push({ - label: this.main.i18nService.t('aboutBitwarden'), - click: () => { - const aboutInformation = this.main.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.main.windowMain.win, { - title: 'Bitwarden', - message: 'Bitwarden', - detail: aboutInformation, - type: 'info', - noLink: true, - buttons: [this.main.i18nService.t('ok'), this.main.i18nService.t('copy')], - }); - if (result === 1) { - clipboard.writeText(aboutInformation); - } - }, - }); + aboutMenuAdditions.push(this.aboutMenuItemOptions); template[template.length - 1].submenu = (template[template.length - 1].submenu as MenuItemConstructorOptions[]).concat(aboutMenuAdditions); diff --git a/src/main/messaging.main.ts b/src/main/messaging.main.ts index b706e80494..ca757130cb 100644 --- a/src/main/messaging.main.ts +++ b/src/main/messaging.main.ts @@ -1,17 +1,7 @@ -import { - app, - ipcMain, -} from 'electron'; - -import { - deletePassword, - getPassword, - setPassword, -} from 'keytar'; +import { ipcMain } from 'electron'; import { Main } from '../main'; -const KeytarService = 'Bitwarden'; const SyncInterval = 5 * 60 * 1000; // 5 minutes export class MessagingMain { @@ -22,25 +12,6 @@ export class MessagingMain { init() { this.scheduleNextSync(); ipcMain.on('messagingService', async (event: any, message: any) => this.onMessage(message)); - - ipcMain.on('keytar', async (event: any, message: any) => { - try { - let val: string = null; - if (message.action && message.key) { - if (message.action === 'getPassword') { - val = await getPassword(KeytarService, message.key); - } else if (message.action === 'setPassword' && message.value) { - await setPassword(KeytarService, message.key, message.value); - } else if (message.action === 'deletePassword') { - await deletePassword(KeytarService, message.key); - } - } - - event.returnValue = val; - } catch { - event.returnValue = null; - } - }); } onMessage(message: any) {