From b9da4457a7ee7897aa6bd81dd63d2fa51a1b5fe2 Mon Sep 17 00:00:00 2001 From: addison Date: Tue, 2 Nov 2021 20:49:49 -0400 Subject: [PATCH] [feature] Enable locking any account from the menu --- src/app/app.component.ts | 34 ++++++------ src/locales/en/messages.json | 4 +- src/main/menu.main.ts | 102 ++++++++++++++++++++++------------- 3 files changed, 83 insertions(+), 57 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index dd74018b..1ad33a7f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -148,13 +148,12 @@ export class AppComponent implements OnInit { this.logOut(!!message.expired); break; case 'lockVault': - await this.vaultTimeoutService.lock(true); + await this.vaultTimeoutService.lock(true, message.userId); break; case 'locked': if (this.modal != null) { this.modal.close(); } - await this.stateService.purge(); this.router.navigate(['lock']); this.notificationsService.updateConnection(); this.updateAppMenu(); @@ -331,24 +330,25 @@ export class AppComponent implements OnInit { const stateAccounts = this.stateService.accounts?.getValue(); if (stateAccounts == null || Object.keys(stateAccounts).length < 1) { this.messagingService.send('updateAppMenu', { accounts: null, activeUserId: null }); - return; - } - - const accounts: { [userId: string]: any } = {}; - for (const i in stateAccounts) { - if (i != null) { - const userId = stateAccounts[i].userId; - accounts[userId] = { - isAuthenticated: await this.stateService.getIsAuthenticated({ - userId: userId, storageLocation: StorageLocation.Memory, - }), - isLocked: await this.vaultTimeoutService.isLocked(userId), - }; + } else { + const accounts: { [userId: string]: any } = {}; + for (const i in stateAccounts) { + if (i != null) { + const userId = stateAccounts[i].userId; + accounts[userId] = { + isAuthenticated: await this.stateService.getIsAuthenticated({ + userId: userId, storageLocation: StorageLocation.Memory, + }), + isLocked: await this.vaultTimeoutService.isLocked(userId), + email: stateAccounts[i].email, + userId: stateAccounts[i].userId, + }; + } } + this.messagingService.send('updateAppMenu', { accounts: accounts, activeUserId: await this.stateService.getUserId() }); } - this.messagingService.send('updateAppMenu', { accounts: accounts, activeUserId: await this.stateService.getUserId() }); } catch (e) { - this.logService.debug(e); + this.logService.error(e); } } diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 9ed8b57c..82e5efe9 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -707,8 +707,8 @@ "loading": { "message": "Loading..." }, - "lockNow": { - "message": "Lock Now" + "lockVault": { + "message": "Lock Vault" }, "passwordGenerator": { "message": "Password Generator" diff --git a/src/main/menu.main.ts b/src/main/menu.main.ts index 38b858d4..e4a75443 100644 --- a/src/main/menu.main.ts +++ b/src/main/menu.main.ts @@ -68,35 +68,60 @@ export class MenuMain extends BaseMenu { this.unlockedRequiredMenuItems = [ this.addNewLogin, this.addNewItem, this.addNewFolder, - this.syncVault, this.exportVault, this.settings, this.lockNow, this.twoStepLogin, this.fingerprintPhrase, + this.syncVault, this.exportVault, this.settings, this.twoStepLogin, this.fingerprintPhrase, this.changeMasterPass, this.premiumMembership, this.passwordGenerator, this.passwordHistory, this.searchVault, this.copyUsername, this.copyPassword]; this.updateApplicationMenuState(); } - updateApplicationMenuState(accounts?: { [userId: string]: { isAuthenticated: boolean, isLocked: boolean }}, activeUserId?: string) { - const isAuthenticated = accounts != null ? - accounts[activeUserId]?.isAuthenticated ?? false : - false; - const isLocked = accounts != null ? - accounts[activeUserId]?.isLocked ?? true : - true; - - this.unlockedRequiredMenuItems.forEach((mi: MenuItem) => { - if (mi != null) { - mi.enabled = isAuthenticated && !isLocked; - } - }); - + updateApplicationMenuState(accounts?: { [userId: string]: { isAuthenticated: boolean, isLocked: boolean, userId: string, email: string }}, activeUserId?: string) { + this.updateAuthBasedMenuState(accounts, activeUserId); if (this.menu != null) { Menu.setApplicationMenu(this.menu); } + } - if (this.logOut != null) { - this.logOut.enabled = isAuthenticated; + private updateAuthBasedMenuState(accounts?: {[userId: string]: { isAuthenticated: boolean, isLocked: boolean, userId: string, email: string}}, activeUserId?: string) { + accounts == null ? + this.lockAuthBasedMenuItems() : + this.tryUnlockAuthBasedMenuItems(accounts, activeUserId); + } + + private lockAuthBasedMenuItems() { + this.logOut.enabled = false; + this.lockNow.enabled = false; + this.unlockedRequiredMenuItems.forEach((mi: MenuItem) => { + if (mi != null) { + mi.enabled = false; + } + }); + } + + private tryUnlockAuthBasedMenuItems(accounts: {[userId: string]: { isAuthenticated: boolean, isLocked: boolean, userId: string, email: string},}, activeUserId: string) { + this.tryUnlockActiveAccountAuthBasedMenuItems(accounts[activeUserId]); + + this.lockNow.enabled = true; + for (const i in accounts) { + if (this.lockNow.submenu.getMenuItemById(`lockNow_${accounts[i].userId}`) == null) { + const options: MenuItemConstructorOptions = { + label: accounts[i].email, + id: `lockNow_${accounts[i].userId}`, + click: () => this.main.messagingService.send('lockVault', { userId: accounts[i].userId }), + }; + this.lockNow.submenu.insert(0, new MenuItem(options)); + } } } + private tryUnlockActiveAccountAuthBasedMenuItems(activeAccount: { isAuthenticated: boolean, isLocked: boolean, userId: string, email: string}) { + this.logOut.enabled = activeAccount.isAuthenticated; + this.unlockedRequiredMenuItems.forEach((mi: MenuItem) => { + if (mi != null) { + mi.enabled = activeAccount.isAuthenticated && !activeAccount.isLocked; + } + }); + } + private initApplicationMenu() { const accountSubmenu: MenuItemConstructorOptions[] = [ { @@ -140,25 +165,6 @@ export class MenuMain extends BaseMenu { id: 'fingerprintPhrase', click: () => this.main.messagingService.send('showFingerprintPhrase'), }, - { type: 'separator' }, - { - label: this.i18nService.t('logOut'), - id: 'logOut', - click: async () => { - const result = await dialog.showMessageBox(this.windowMain.win, { - title: this.i18nService.t('logOut'), - message: this.i18nService.t('logOut'), - detail: this.i18nService.t('logOutConfirmation'), - buttons: [this.i18nService.t('logOut'), this.i18nService.t('cancel')], - cancelId: 1, - defaultId: 0, - noLink: true, - }); - if (result.response === 0) { - this.main.messagingService.send('logout'); - } - }, - }, ]; this.editMenuItemOptions.submenu = (this.editMenuItemOptions.submenu as MenuItemConstructorOptions[]).concat([ @@ -413,10 +419,30 @@ export class MenuMain extends BaseMenu { accelerator: 'CmdOrCtrl+,', }, { - label: this.main.i18nService.t('lockNow'), + label: this.main.i18nService.t('lockVault'), id: 'lockNow', - click: () => this.main.messagingService.send('lockVault'), accelerator: 'CmdOrCtrl+L', + submenu: [ + // List of vaults + ], + }, + { + label: this.i18nService.t('logOut'), + id: 'logOut', + click: async () => { + const result = await dialog.showMessageBox(this.windowMain.win, { + title: this.i18nService.t('logOut'), + message: this.i18nService.t('logOut'), + detail: this.i18nService.t('logOutConfirmation'), + buttons: [this.i18nService.t('logOut'), this.i18nService.t('cancel')], + cancelId: 1, + defaultId: 0, + noLink: true, + }); + if (result.response === 0) { + this.main.messagingService.send('logout'); + } + }, }, ];