From 0eb7fe1407dab65b8db1e62c267fba0d92c71b99 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 15 Oct 2021 15:03:25 +0200 Subject: [PATCH 01/17] Extract logic for notificationBar into new NotificationBackground class --- src/background/main.background.ts | 10 +- src/background/notification.background.ts | 379 ++++++++++++++++++++++ src/background/runtime.background.ts | 282 +--------------- 3 files changed, 389 insertions(+), 282 deletions(-) create mode 100644 src/background/notification.background.ts diff --git a/src/background/main.background.ts b/src/background/main.background.ts index f3538028db1..d7f469a8904 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -71,6 +71,7 @@ import CommandsBackground from './commands.background'; import ContextMenusBackground from './contextMenus.background'; import IdleBackground from './idle.background'; import { NativeMessagingBackground } from './nativeMessaging.background'; +import NotificationBackground from './notification.background'; import RuntimeBackground from './runtime.background'; import TabsBackground from './tabs.background'; import WebRequestBackground from './webRequest.background'; @@ -135,6 +136,7 @@ export default class MainBackground { private tabsBackground: TabsBackground; private webRequestBackground: WebRequestBackground; private windowsBackground: WindowsBackground; + private notificationBackground: NotificationBackground; private sidebarAction: any; private buildingContextMenu: boolean; @@ -237,15 +239,16 @@ export default class MainBackground { opr.sidebarAction : (window as any).chrome.sidebarAction; // Background - this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.cipherService, + this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.platformUtilsService as BrowserPlatformUtilsService, this.storageService, this.i18nService, - this.notificationsService, this.systemService, this.vaultTimeoutService, - this.environmentService, this.policyService, this.userService, this.messagingService, this.folderService); + this.notificationsService, this.systemService, this.environmentService, this.messagingService); this.nativeMessagingBackground = new NativeMessagingBackground(this.storageService, this.cryptoService, this.cryptoFunctionService, this.vaultTimeoutService, this.runtimeBackground, this.i18nService, this.userService, this.messagingService, this.appIdService, this.platformUtilsService); this.commandsBackground = new CommandsBackground(this, this.passwordGenerationService, this.platformUtilsService, this.vaultTimeoutService); + this.notificationBackground = new NotificationBackground(this, this.autofillService, this.cipherService, + this.storageService, this.vaultTimeoutService, this.policyService, this.folderService); this.tabsBackground = new TabsBackground(this); this.contextMenusBackground = new ContextMenusBackground(this, this.cipherService, this.passwordGenerationService, @@ -276,6 +279,7 @@ export default class MainBackground { await (this.i18nService as I18nService).init(); await (this.eventService as EventService).init(true); await this.runtimeBackground.init(); + await this.notificationBackground.init(); await this.commandsBackground.init(); await this.tabsBackground.init(); diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts new file mode 100644 index 00000000000..7f1377e0083 --- /dev/null +++ b/src/background/notification.background.ts @@ -0,0 +1,379 @@ +import { CipherType } from 'jslib-common/enums/cipherType'; + +import { CipherView } from 'jslib-common/models/view/cipherView'; +import { LoginUriView } from 'jslib-common/models/view/loginUriView'; +import { LoginView } from 'jslib-common/models/view/loginView'; + +import { CipherService } from 'jslib-common/abstractions/cipher.service'; +import { FolderService } from 'jslib-common/abstractions/folder.service'; +import { PolicyService } from 'jslib-common/abstractions/policy.service'; +import { StorageService } from 'jslib-common/abstractions/storage.service'; +import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service'; +import { ConstantsService } from 'jslib-common/services/constants.service'; +import { AutofillService } from '../services/abstractions/autofill.service'; + +import { BrowserApi } from '../browser/browserApi'; + +import MainBackground from './main.background'; + +import { Utils } from 'jslib-common/misc/utils'; + +import { PolicyType } from 'jslib-common/enums/policyType'; + +import AddChangePasswordQueueMessage from './models/addChangePasswordQueueMessage'; +import AddLoginQueueMessage from './models/addLoginQueueMessage'; + +export default class NotificationBackground { + constructor(private main: MainBackground, private autofillService: AutofillService, + private cipherService: CipherService, private storageService: StorageService, + private vaultTimeoutService: VaultTimeoutService, private policyService: PolicyService, + private folderService: FolderService) { + } + + async init() { + if (!chrome.runtime) { + return; + } + + BrowserApi.messageListener('notification.background', async (msg: any, sender: any, sendResponse: any) => { + await this.processMessage(msg, sender, sendResponse); + }); + + this.cleanupNotificationQueue(); + } + + async checkNotificationQueue(tab: any = null): Promise { + if (this.main.notificationQueue.length === 0) { + return; + } + + if (tab != null) { + this.doNotificationQueueCheck(tab); + return; + } + + const currentTab = await BrowserApi.getTabFromCurrentWindow(); + if (currentTab != null) { + this.doNotificationQueueCheck(currentTab); + } + } + + private cleanupNotificationQueue() { + for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { + if (this.main.notificationQueue[i].expires < new Date()) { + this.main.notificationQueue.splice(i, 1); + } + } + setTimeout(() => this.cleanupNotificationQueue(), 2 * 60 * 1000); // check every 2 minutes + } + + private doNotificationQueueCheck(tab: any) { + if (tab == null) { + return; + } + + const tabDomain = Utils.getDomain(tab.url); + if (tabDomain == null) { + return; + } + + for (let i = 0; i < this.main.notificationQueue.length; i++) { + if (this.main.notificationQueue[i].tabId !== tab.id || this.main.notificationQueue[i].domain !== tabDomain) { + continue; + } + + if (this.main.notificationQueue[i].type === 'addLogin') { + BrowserApi.tabSendMessageData(tab, 'openNotificationBar', { + type: 'add', + typeData: { + isVaultLocked: this.main.notificationQueue[i].wasVaultLocked, + }, + }); + } else if (this.main.notificationQueue[i].type === 'changePassword') { + BrowserApi.tabSendMessageData(tab, 'openNotificationBar', { + type: 'change', + typeData: { + isVaultLocked: this.main.notificationQueue[i].wasVaultLocked, + }, + }); + } + break; + } + } + + private removeTabFromNotificationQueue(tab: any) { + for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { + if (this.main.notificationQueue[i].tabId === tab.id) { + this.main.notificationQueue.splice(i, 1); + } + } + } + + async processMessage(msg: any, sender: any, sendResponse: any) { + switch (msg.command) { + case 'bgGetDataForTab': + await this.getDataForTab(sender.tab, msg.responseCommand); + break; + case 'bgCloseNotificationBar': + await BrowserApi.tabSendMessageData(sender.tab, 'closeNotificationBar'); + break; + case 'bgAdjustNotificationBar': + await BrowserApi.tabSendMessageData(sender.tab, 'adjustNotificationBar', msg.data); + break; + case 'bgAddLogin': + await this.addLogin(msg.login, sender.tab); + break; + case 'bgChangedPassword': + await this.changedPassword(msg.data, sender.tab); + break; + case 'bgAddClose': + case 'bgChangeClose': + this.removeTabFromNotificationQueue(sender.tab); + break; + case 'bgAddSave': + case 'bgChangeSave': + await this.saveOrUpdateCredentials(sender.tab, msg.folder); + break; + case 'bgNeverSave': + await this.saveNever(sender.tab); + break; + case 'collectPageDetailsResponse': + switch (msg.sender) { + case 'notificationBar': + console.log('collectPageDetailsResponse for notificationBar received', msg.tab) + const forms = this.autofillService.getFormsWithPasswordFields(msg.details); + await BrowserApi.tabSendMessageData(msg.tab, 'notificationBarPageDetails', { + details: msg.details, + forms: forms, + }); + break; + default: + break; + } + break; + default: + break; + } + } + + private async addLogin(loginInfo: any, tab: any) { + const loginDomain = Utils.getDomain(loginInfo.url); + if (loginDomain == null) { + return; + } + + let normalizedUsername = loginInfo.username; + if (normalizedUsername != null) { + normalizedUsername = normalizedUsername.toLowerCase(); + } + + if (await this.vaultTimeoutService.isLocked()) { + this.pushAddLoginToQueue(loginDomain, loginInfo, tab, true); + return; + } + + const ciphers = await this.cipherService.getAllDecryptedForUrl(loginInfo.url); + const usernameMatches = ciphers.filter(c => + c.login.username != null && c.login.username.toLowerCase() === normalizedUsername); + if (usernameMatches.length === 0) { + const disabledAddLogin = await this.storageService.get( + ConstantsService.disableAddLoginNotificationKey); + if (disabledAddLogin) { + return; + } + + if (!(await this.allowPersonalOwnership())) { + return; + } + + this.pushAddLoginToQueue(loginDomain, loginInfo, tab); + + } else if (usernameMatches.length === 1 && usernameMatches[0].login.password !== loginInfo.password) { + const disabledChangePassword = await this.storageService.get( + ConstantsService.disableChangedPasswordNotificationKey); + if (disabledChangePassword) { + return; + } + this.pushChangePasswordToQueue(usernameMatches[0].id, loginDomain, loginInfo.password, tab); + } + } + + private async pushAddLoginToQueue(loginDomain: string, loginInfo: any, tab: any, isVaultLocked: boolean = false) { + // remove any old messages for this tab + this.removeTabFromNotificationQueue(tab); + const message: AddLoginQueueMessage = { + type: 'addLogin', + username: loginInfo.username, + password: loginInfo.password, + domain: loginDomain, + uri: loginInfo.url, + tabId: tab.id, + expires: new Date((new Date()).getTime() + 5 * 60000), // 5 minutes + wasVaultLocked: isVaultLocked, + }; + this.main.notificationQueue.push(message); + await this.checkNotificationQueue(tab); + } + + private async changedPassword(changeData: any, tab: any) { + const loginDomain = Utils.getDomain(changeData.url); + if (loginDomain == null) { + return; + } + + if (await this.vaultTimeoutService.isLocked()) { + this.pushChangePasswordToQueue(null, loginDomain, changeData.newPassword, tab, true); + return; + } + + let id: string = null; + const ciphers = await this.cipherService.getAllDecryptedForUrl(changeData.url); + if (changeData.currentPassword != null) { + const passwordMatches = ciphers.filter(c => c.login.password === changeData.currentPassword); + if (passwordMatches.length === 1) { + id = passwordMatches[0].id; + } + } else if (ciphers.length === 1) { + id = ciphers[0].id; + } + if (id != null) { + this.pushChangePasswordToQueue(id, loginDomain, changeData.newPassword, tab); + } + } + + private async pushChangePasswordToQueue(cipherId: string, loginDomain: string, newPassword: string, tab: any, isVaultLocked: boolean = false) { + // remove any old messages for this tab + this.removeTabFromNotificationQueue(tab); + const message: AddChangePasswordQueueMessage = { + type: 'changePassword', + cipherId: cipherId, + newPassword: newPassword, + domain: loginDomain, + tabId: tab.id, + expires: new Date((new Date()).getTime() + 5 * 60000), // 5 minutes + wasVaultLocked: isVaultLocked, + }; + this.main.notificationQueue.push(message); + await this.checkNotificationQueue(tab); + } + + private async saveOrUpdateCredentials(tab: any, folderId?: string) { + for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { + const queueMessage = this.main.notificationQueue[i]; + if (queueMessage.tabId !== tab.id || + (queueMessage.type !== 'addLogin' && queueMessage.type !== 'changePassword')) { + continue; + } + + const tabDomain = Utils.getDomain(tab.url); + if (tabDomain != null && tabDomain !== queueMessage.domain) { + continue; + } + + this.main.notificationQueue.splice(i, 1); + BrowserApi.tabSendMessageData(tab, 'closeNotificationBar'); + + if (queueMessage.type === 'changePassword') { + const message = (queueMessage as AddChangePasswordQueueMessage); + const cipher = await this.getDecryptedCipherById(message.cipherId); + if (cipher == null) { + return; + } + await this.updateCipher(cipher, message.newPassword); + return; + } + + if (!queueMessage.wasVaultLocked) { + await this.createNewCipher(queueMessage, folderId); + } + + // If the vault was locked, check if a cipher needs updating instead of creating a new one + if (queueMessage.type === 'addLogin' && queueMessage.wasVaultLocked === true) { + const message = (queueMessage as AddLoginQueueMessage); + const ciphers = await this.cipherService.getAllDecryptedForUrl(message.uri); + const usernameMatches = ciphers.filter(c => c.login.username != null && + c.login.username.toLowerCase() === message.username); + + if (usernameMatches.length >= 1) { + await this.updateCipher(usernameMatches[0], message.password); + return; + } + + await this.createNewCipher(message, folderId); + } + } + } + + private async createNewCipher(queueMessage: AddLoginQueueMessage, folderId: string) { + const loginModel = new LoginView(); + const loginUri = new LoginUriView(); + loginUri.uri = queueMessage.uri; + loginModel.uris = [loginUri]; + loginModel.username = queueMessage.username; + loginModel.password = queueMessage.password; + const model = new CipherView(); + model.name = Utils.getHostname(queueMessage.uri) || queueMessage.domain; + model.name = model.name.replace(/^www\./, ''); + model.type = CipherType.Login; + model.login = loginModel; + + if (!Utils.isNullOrWhitespace(folderId)) { + const folders = await this.folderService.getAllDecrypted(); + if (folders.some(x => x.id === folderId)) { + model.folderId = folderId; + } + } + + const cipher = await this.cipherService.encrypt(model); + await this.cipherService.saveWithServer(cipher); + } + + private async getDecryptedCipherById(cipherId: string) { + const cipher = await this.cipherService.get(cipherId); + if (cipher != null && cipher.type === CipherType.Login) { + return await cipher.decrypt(); + } + return null; + } + + private async updateCipher(cipher: CipherView, newPassword: string) { + if (cipher != null && cipher.type === CipherType.Login) { + cipher.login.password = newPassword; + const newCipher = await this.cipherService.encrypt(cipher); + await this.cipherService.saveWithServer(newCipher); + } + } + + private async saveNever(tab: any) { + for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { + const queueMessage = this.main.notificationQueue[i]; + if (queueMessage.tabId !== tab.id || queueMessage.type !== 'addLogin') { + continue; + } + + const tabDomain = Utils.getDomain(tab.url); + if (tabDomain != null && tabDomain !== queueMessage.domain) { + continue; + } + + this.main.notificationQueue.splice(i, 1); + BrowserApi.tabSendMessageData(tab, 'closeNotificationBar'); + + const hostname = Utils.getHostname(tab.url); + await this.cipherService.saveNeverDomain(hostname); + } + } + + private async getDataForTab(tab: any, responseCommand: string) { + const responseData: any = {}; + if (responseCommand === 'notificationBarGetFoldersList') { + responseData.folders = await this.folderService.getAllDecrypted(); + } + + await BrowserApi.tabSendMessageData(tab, responseCommand, responseData); + } + + private async allowPersonalOwnership(): Promise { + return !await this.policyService.policyAppliesToUser(PolicyType.PersonalOwnership); + } +} diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index a46d174aac6..a68c61cf660 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -1,20 +1,9 @@ -import { CipherType } from 'jslib-common/enums/cipherType'; - -import { CipherView } from 'jslib-common/models/view/cipherView'; -import { LoginUriView } from 'jslib-common/models/view/loginUriView'; -import { LoginView } from 'jslib-common/models/view/loginView'; - -import { CipherService } from 'jslib-common/abstractions/cipher.service'; import { EnvironmentService } from 'jslib-common/abstractions/environment.service'; -import { FolderService } from 'jslib-common/abstractions/folder.service'; import { I18nService } from 'jslib-common/abstractions/i18n.service'; import { MessagingService } from 'jslib-common/abstractions/messaging.service'; import { NotificationsService } from 'jslib-common/abstractions/notifications.service'; -import { PolicyService } from 'jslib-common/abstractions/policy.service'; import { StorageService } from 'jslib-common/abstractions/storage.service'; import { SystemService } from 'jslib-common/abstractions/system.service'; -import { UserService } from 'jslib-common/abstractions/user.service'; -import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service'; import { ConstantsService } from 'jslib-common/services/constants.service'; import { AutofillService } from '../services/abstractions/autofill.service'; import BrowserPlatformUtilsService from '../services/browserPlatformUtils.service'; @@ -39,13 +28,10 @@ export default class RuntimeBackground { private lockedVaultPendingNotifications: any[] = []; constructor(private main: MainBackground, private autofillService: AutofillService, - private cipherService: CipherService, private platformUtilsService: BrowserPlatformUtilsService, + private platformUtilsService: BrowserPlatformUtilsService, private storageService: StorageService, private i18nService: I18nService, - private notificationsService: NotificationsService, - private systemService: SystemService, private vaultTimeoutService: VaultTimeoutService, - private environmentService: EnvironmentService, private policyService: PolicyService, - private userService: UserService, private messagingService: MessagingService, - private folderService: FolderService) { + private notificationsService: NotificationsService, private systemService: SystemService, + private environmentService: EnvironmentService, private messagingService: MessagingService) { // onInstalled listener must be wired up before anything else, so we do it in the ctor chrome.runtime.onInstalled.addListener((details: any) => { @@ -108,35 +94,9 @@ export default class RuntimeBackground { case 'showDialogResolve': this.platformUtilsService.resolveDialogPromise(msg.dialogId, msg.confirmed); break; - case 'bgGetDataForTab': - await this.getDataForTab(sender.tab, msg.responseCommand); - break; - case 'bgCloseNotificationBar': - await BrowserApi.tabSendMessageData(sender.tab, 'closeNotificationBar'); - break; - case 'bgAdjustNotificationBar': - await BrowserApi.tabSendMessageData(sender.tab, 'adjustNotificationBar', msg.data); - break; case 'bgCollectPageDetails': await this.main.collectPageDetailsForContentScript(sender.tab, msg.sender, sender.frameId); break; - case 'bgAddLogin': - await this.addLogin(msg.login, sender.tab); - break; - case 'bgChangedPassword': - await this.changedPassword(msg.data, sender.tab); - break; - case 'bgAddClose': - case 'bgChangeClose': - this.removeTabFromNotificationQueue(sender.tab); - break; - case 'bgAddSave': - case 'bgChangeSave': - await this.saveOrUpdateCredentials(sender.tab, msg.folder); - break; - case 'bgNeverSave': - await this.saveNever(sender.tab); - break; case 'bgUpdateContextMenu': case 'editedCipher': case 'addedCipher': @@ -148,13 +108,6 @@ export default class RuntimeBackground { break; case 'collectPageDetailsResponse': switch (msg.sender) { - case 'notificationBar': - const forms = this.autofillService.getFormsWithPasswordFields(msg.details); - await BrowserApi.tabSendMessageData(msg.tab, 'notificationBarPageDetails', { - details: msg.details, - forms: forms, - }); - break; case 'autofiller': case 'autofill_cmd': const totpCode = await this.autofillService.doAutoFillActiveTab([{ @@ -237,222 +190,6 @@ export default class RuntimeBackground { this.pageDetailsToAutoFill = []; } - private async saveOrUpdateCredentials(tab: any, folderId?: string) { - for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { - const queueMessage = this.main.notificationQueue[i]; - if (queueMessage.tabId !== tab.id || - (queueMessage.type !== 'addLogin' && queueMessage.type !== 'changePassword')) { - continue; - } - - const tabDomain = Utils.getDomain(tab.url); - if (tabDomain != null && tabDomain !== queueMessage.domain) { - continue; - } - - this.main.notificationQueue.splice(i, 1); - BrowserApi.tabSendMessageData(tab, 'closeNotificationBar'); - - if (queueMessage.type === 'changePassword') { - const message = (queueMessage as AddChangePasswordQueueMessage); - const cipher = await this.getDecryptedCipherById(message.cipherId); - if (cipher == null) { - return; - } - await this.updateCipher(cipher, message.newPassword); - return; - } - - if (!queueMessage.wasVaultLocked) { - await this.createNewCipher(queueMessage, folderId); - } - - // If the vault was locked, check if a cipher needs updating instead of creating a new one - if (queueMessage.type === 'addLogin' && queueMessage.wasVaultLocked === true) { - const message = (queueMessage as AddLoginQueueMessage); - const ciphers = await this.cipherService.getAllDecryptedForUrl(message.uri); - const usernameMatches = ciphers.filter(c => c.login.username != null && - c.login.username.toLowerCase() === message.username); - - if (usernameMatches.length >= 1) { - await this.updateCipher(usernameMatches[0], message.password); - return; - } - - await this.createNewCipher(message, folderId); - } - } - } - - private async createNewCipher(queueMessage: AddLoginQueueMessage, folderId: string) { - const loginModel = new LoginView(); - const loginUri = new LoginUriView(); - loginUri.uri = queueMessage.uri; - loginModel.uris = [loginUri]; - loginModel.username = queueMessage.username; - loginModel.password = queueMessage.password; - const model = new CipherView(); - model.name = Utils.getHostname(queueMessage.uri) || queueMessage.domain; - model.name = model.name.replace(/^www\./, ''); - model.type = CipherType.Login; - model.login = loginModel; - - if (!Utils.isNullOrWhitespace(folderId)) { - const folders = await this.folderService.getAllDecrypted(); - if (folders.some(x => x.id === folderId)) { - model.folderId = folderId; - } - } - - const cipher = await this.cipherService.encrypt(model); - await this.cipherService.saveWithServer(cipher); - } - - private async getDecryptedCipherById(cipherId: string) { - const cipher = await this.cipherService.get(cipherId); - if (cipher != null && cipher.type === CipherType.Login) { - return await cipher.decrypt(); - } - return null; - } - - private async updateCipher(cipher: CipherView, newPassword: string) { - if (cipher != null && cipher.type === CipherType.Login) { - cipher.login.password = newPassword; - const newCipher = await this.cipherService.encrypt(cipher); - await this.cipherService.saveWithServer(newCipher); - } - } - - private async saveNever(tab: any) { - for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { - const queueMessage = this.main.notificationQueue[i]; - if (queueMessage.tabId !== tab.id || queueMessage.type !== 'addLogin') { - continue; - } - - const tabDomain = Utils.getDomain(tab.url); - if (tabDomain != null && tabDomain !== queueMessage.domain) { - continue; - } - - this.main.notificationQueue.splice(i, 1); - BrowserApi.tabSendMessageData(tab, 'closeNotificationBar'); - - const hostname = Utils.getHostname(tab.url); - await this.cipherService.saveNeverDomain(hostname); - } - } - - private async addLogin(loginInfo: any, tab: any) { - const loginDomain = Utils.getDomain(loginInfo.url); - if (loginDomain == null) { - return; - } - - let normalizedUsername = loginInfo.username; - if (normalizedUsername != null) { - normalizedUsername = normalizedUsername.toLowerCase(); - } - - if (await this.vaultTimeoutService.isLocked()) { - this.pushAddLoginToQueue(loginDomain, loginInfo, tab, true); - return; - } - - const ciphers = await this.cipherService.getAllDecryptedForUrl(loginInfo.url); - const usernameMatches = ciphers.filter(c => - c.login.username != null && c.login.username.toLowerCase() === normalizedUsername); - if (usernameMatches.length === 0) { - const disabledAddLogin = await this.storageService.get( - ConstantsService.disableAddLoginNotificationKey); - if (disabledAddLogin) { - return; - } - - if (!(await this.allowPersonalOwnership())) { - return; - } - - this.pushAddLoginToQueue(loginDomain, loginInfo, tab); - - } else if (usernameMatches.length === 1 && usernameMatches[0].login.password !== loginInfo.password) { - const disabledChangePassword = await this.storageService.get( - ConstantsService.disableChangedPasswordNotificationKey); - if (disabledChangePassword) { - return; - } - this.pushChangePasswordToQueue(usernameMatches[0].id, loginDomain, loginInfo.password, tab); - } - } - - private async pushAddLoginToQueue(loginDomain: string, loginInfo: any, tab: any, isVaultLocked: boolean = false) { - // remove any old messages for this tab - this.removeTabFromNotificationQueue(tab); - const message: AddLoginQueueMessage = { - type: 'addLogin', - username: loginInfo.username, - password: loginInfo.password, - domain: loginDomain, - uri: loginInfo.url, - tabId: tab.id, - expires: new Date((new Date()).getTime() + 5 * 60000), // 5 minutes - wasVaultLocked: isVaultLocked, - }; - this.main.notificationQueue.push(message); - await this.main.checkNotificationQueue(tab); - } - - private async changedPassword(changeData: any, tab: any) { - const loginDomain = Utils.getDomain(changeData.url); - if (loginDomain == null) { - return; - } - - if (await this.vaultTimeoutService.isLocked()) { - this.pushChangePasswordToQueue(null, loginDomain, changeData.newPassword, tab, true); - return; - } - - let id: string = null; - const ciphers = await this.cipherService.getAllDecryptedForUrl(changeData.url); - if (changeData.currentPassword != null) { - const passwordMatches = ciphers.filter(c => c.login.password === changeData.currentPassword); - if (passwordMatches.length === 1) { - id = passwordMatches[0].id; - } - } else if (ciphers.length === 1) { - id = ciphers[0].id; - } - if (id != null) { - this.pushChangePasswordToQueue(id, loginDomain, changeData.newPassword, tab); - } - } - - private async pushChangePasswordToQueue(cipherId: string, loginDomain: string, newPassword: string, tab: any, isVaultLocked: boolean = false) { - // remove any old messages for this tab - this.removeTabFromNotificationQueue(tab); - const message: AddChangePasswordQueueMessage = { - type: 'changePassword', - cipherId: cipherId, - newPassword: newPassword, - domain: loginDomain, - tabId: tab.id, - expires: new Date((new Date()).getTime() + 5 * 60000), // 5 minutes - wasVaultLocked: isVaultLocked, - }; - this.main.notificationQueue.push(message); - await this.main.checkNotificationQueue(tab); - } - - private removeTabFromNotificationQueue(tab: any) { - for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { - if (this.main.notificationQueue[i].tabId === tab.id) { - this.main.notificationQueue.splice(i, 1); - } - } - } - private async checkOnInstalled() { setTimeout(async () => { if (this.onInstalledReason != null) { @@ -479,17 +216,4 @@ export default class RuntimeBackground { await this.storageService.save(ConstantsService.vaultTimeoutActionKey, 'lock'); } } - - private async getDataForTab(tab: any, responseCommand: string) { - const responseData: any = {}; - if (responseCommand === 'notificationBarGetFoldersList') { - responseData.folders = await this.folderService.getAllDecrypted(); - } - - await BrowserApi.tabSendMessageData(tab, responseCommand, responseData); - } - - private async allowPersonalOwnership(): Promise { - return !await this.policyService.policyAppliesToUser(PolicyType.PersonalOwnership); - } } From 7388cd174ef4b49513f2c61a9d3f037036b9b1eb Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 15 Oct 2021 15:09:13 +0200 Subject: [PATCH 02/17] Move notificationQueue from main into notification.background --- src/background/main.background.ts | 63 +---------------------- src/background/notification.background.ts | 45 ++++++++-------- src/background/tabs.background.ts | 7 +-- 3 files changed, 29 insertions(+), 86 deletions(-) diff --git a/src/background/main.background.ts b/src/background/main.background.ts index d7f469a8904..e2ded7cbc07 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -127,7 +127,6 @@ export default class MainBackground { onUpdatedRan: boolean; onReplacedRan: boolean; loginToAutoFill: any = null; - notificationQueue: any[] = []; private commandsBackground: CommandsBackground; private contextMenusBackground: ContextMenusBackground; @@ -250,7 +249,7 @@ export default class MainBackground { this.notificationBackground = new NotificationBackground(this, this.autofillService, this.cipherService, this.storageService, this.vaultTimeoutService, this.policyService, this.folderService); - this.tabsBackground = new TabsBackground(this); + this.tabsBackground = new TabsBackground(this, this.notificationBackground); this.contextMenusBackground = new ContextMenusBackground(this, this.cipherService, this.passwordGenerationService, this.platformUtilsService, this.vaultTimeoutService, this.eventService, this.totpService); this.idleBackground = new IdleBackground(this.vaultTimeoutService, this.storageService, @@ -292,7 +291,6 @@ export default class MainBackground { setTimeout(async () => { await this.environmentService.setUrlsFromStorage(); await this.setIcon(); - this.cleanupNotificationQueue(); this.fullSync(true); setTimeout(() => this.notificationsService.init(), 2500); resolve(); @@ -390,22 +388,6 @@ export default class MainBackground { }, options); } - async checkNotificationQueue(tab: any = null): Promise { - if (this.notificationQueue.length === 0) { - return; - } - - if (tab != null) { - this.doNotificationQueueCheck(tab); - return; - } - - const currentTab = await BrowserApi.getTabFromCurrentWindow(); - if (currentTab != null) { - this.doNotificationQueueCheck(currentTab); - } - } - async openPopup() { // Chrome APIs cannot open popup @@ -657,49 +639,6 @@ export default class MainBackground { return title.replace(/&/g, '&&'); } - private cleanupNotificationQueue() { - for (let i = this.notificationQueue.length - 1; i >= 0; i--) { - if (this.notificationQueue[i].expires < new Date()) { - this.notificationQueue.splice(i, 1); - } - } - setTimeout(() => this.cleanupNotificationQueue(), 2 * 60 * 1000); // check every 2 minutes - } - - private doNotificationQueueCheck(tab: any) { - if (tab == null) { - return; - } - - const tabDomain = Utils.getDomain(tab.url); - if (tabDomain == null) { - return; - } - - for (let i = 0; i < this.notificationQueue.length; i++) { - if (this.notificationQueue[i].tabId !== tab.id || this.notificationQueue[i].domain !== tabDomain) { - continue; - } - - if (this.notificationQueue[i].type === 'addLogin') { - BrowserApi.tabSendMessageData(tab, 'openNotificationBar', { - type: 'add', - typeData: { - isVaultLocked: this.notificationQueue[i].wasVaultLocked, - }, - }); - } else if (this.notificationQueue[i].type === 'changePassword') { - BrowserApi.tabSendMessageData(tab, 'openNotificationBar', { - type: 'change', - typeData: { - isVaultLocked: this.notificationQueue[i].wasVaultLocked, - }, - }); - } - break; - } - } - private async fullSync(override: boolean = false) { const syncInternal = 6 * 60 * 60 * 1000; // 6 hours const lastSync = await this.syncService.getLastSync(); diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index 7f1377e0083..12ded645c6b 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -24,6 +24,9 @@ import AddChangePasswordQueueMessage from './models/addChangePasswordQueueMessag import AddLoginQueueMessage from './models/addLoginQueueMessage'; export default class NotificationBackground { + + private notificationQueue: any[] = []; + constructor(private main: MainBackground, private autofillService: AutofillService, private cipherService: CipherService, private storageService: StorageService, private vaultTimeoutService: VaultTimeoutService, private policyService: PolicyService, @@ -43,7 +46,7 @@ export default class NotificationBackground { } async checkNotificationQueue(tab: any = null): Promise { - if (this.main.notificationQueue.length === 0) { + if (this.notificationQueue.length === 0) { return; } @@ -59,9 +62,9 @@ export default class NotificationBackground { } private cleanupNotificationQueue() { - for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { - if (this.main.notificationQueue[i].expires < new Date()) { - this.main.notificationQueue.splice(i, 1); + for (let i = this.notificationQueue.length - 1; i >= 0; i--) { + if (this.notificationQueue[i].expires < new Date()) { + this.notificationQueue.splice(i, 1); } } setTimeout(() => this.cleanupNotificationQueue(), 2 * 60 * 1000); // check every 2 minutes @@ -77,23 +80,23 @@ export default class NotificationBackground { return; } - for (let i = 0; i < this.main.notificationQueue.length; i++) { - if (this.main.notificationQueue[i].tabId !== tab.id || this.main.notificationQueue[i].domain !== tabDomain) { + for (let i = 0; i < this.notificationQueue.length; i++) { + if (this.notificationQueue[i].tabId !== tab.id || this.notificationQueue[i].domain !== tabDomain) { continue; } - if (this.main.notificationQueue[i].type === 'addLogin') { + if (this.notificationQueue[i].type === 'addLogin') { BrowserApi.tabSendMessageData(tab, 'openNotificationBar', { type: 'add', typeData: { - isVaultLocked: this.main.notificationQueue[i].wasVaultLocked, + isVaultLocked: this.notificationQueue[i].wasVaultLocked, }, }); - } else if (this.main.notificationQueue[i].type === 'changePassword') { + } else if (this.notificationQueue[i].type === 'changePassword') { BrowserApi.tabSendMessageData(tab, 'openNotificationBar', { type: 'change', typeData: { - isVaultLocked: this.main.notificationQueue[i].wasVaultLocked, + isVaultLocked: this.notificationQueue[i].wasVaultLocked, }, }); } @@ -102,9 +105,9 @@ export default class NotificationBackground { } private removeTabFromNotificationQueue(tab: any) { - for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { - if (this.main.notificationQueue[i].tabId === tab.id) { - this.main.notificationQueue.splice(i, 1); + for (let i = this.notificationQueue.length - 1; i >= 0; i--) { + if (this.notificationQueue[i].tabId === tab.id) { + this.notificationQueue.splice(i, 1); } } } @@ -211,7 +214,7 @@ export default class NotificationBackground { expires: new Date((new Date()).getTime() + 5 * 60000), // 5 minutes wasVaultLocked: isVaultLocked, }; - this.main.notificationQueue.push(message); + this.notificationQueue.push(message); await this.checkNotificationQueue(tab); } @@ -253,13 +256,13 @@ export default class NotificationBackground { expires: new Date((new Date()).getTime() + 5 * 60000), // 5 minutes wasVaultLocked: isVaultLocked, }; - this.main.notificationQueue.push(message); + this.notificationQueue.push(message); await this.checkNotificationQueue(tab); } private async saveOrUpdateCredentials(tab: any, folderId?: string) { - for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { - const queueMessage = this.main.notificationQueue[i]; + for (let i = this.notificationQueue.length - 1; i >= 0; i--) { + const queueMessage = this.notificationQueue[i]; if (queueMessage.tabId !== tab.id || (queueMessage.type !== 'addLogin' && queueMessage.type !== 'changePassword')) { continue; @@ -270,7 +273,7 @@ export default class NotificationBackground { continue; } - this.main.notificationQueue.splice(i, 1); + this.notificationQueue.splice(i, 1); BrowserApi.tabSendMessageData(tab, 'closeNotificationBar'); if (queueMessage.type === 'changePassword') { @@ -345,8 +348,8 @@ export default class NotificationBackground { } private async saveNever(tab: any) { - for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) { - const queueMessage = this.main.notificationQueue[i]; + for (let i = this.notificationQueue.length - 1; i >= 0; i--) { + const queueMessage = this.notificationQueue[i]; if (queueMessage.tabId !== tab.id || queueMessage.type !== 'addLogin') { continue; } @@ -356,7 +359,7 @@ export default class NotificationBackground { continue; } - this.main.notificationQueue.splice(i, 1); + this.notificationQueue.splice(i, 1); BrowserApi.tabSendMessageData(tab, 'closeNotificationBar'); const hostname = Utils.getHostname(tab.url); diff --git a/src/background/tabs.background.ts b/src/background/tabs.background.ts index 8f4d4e12b1b..7ba7a75a3dd 100644 --- a/src/background/tabs.background.ts +++ b/src/background/tabs.background.ts @@ -1,9 +1,10 @@ import MainBackground from './main.background'; +import NotificationBackground from './notification.background'; export default class TabsBackground { private tabs: any; - constructor(private main: MainBackground) { + constructor(private main: MainBackground, private notificationBackground: NotificationBackground) { this.tabs = chrome.tabs; } @@ -23,7 +24,7 @@ export default class TabsBackground { return; } this.main.onReplacedRan = true; - await this.main.checkNotificationQueue(); + await this.notificationBackground.checkNotificationQueue(); await this.main.refreshBadgeAndMenu(); this.main.messagingService.send('tabReplaced'); this.main.messagingService.send('tabChanged'); @@ -34,7 +35,7 @@ export default class TabsBackground { return; } this.main.onUpdatedRan = true; - await this.main.checkNotificationQueue(); + await this.notificationBackground.checkNotificationQueue(); await this.main.refreshBadgeAndMenu(); this.main.messagingService.send('tabUpdated'); this.main.messagingService.send('tabChanged'); From 9c0bfd28db142c64df09b346812b413ff87fc9c6 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 15 Oct 2021 15:20:00 +0200 Subject: [PATCH 03/17] Close login tab before executing existing unlock flow --- src/background/runtime.background.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index a68c61cf660..44919c9c74a 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -54,21 +54,19 @@ export default class RuntimeBackground { switch (msg.command) { case 'loggedIn': case 'unlocked': + if (this.lockedVaultPendingNotifications.length > 0) { + await BrowserApi.closeLoginTab(); + + if (item?.sender?.tab?.id) { + await BrowserApi.focusSpecifiedTab(item.sender.tab.id); + } + await this.processMessage(item.msg, item.sender, null); + } + await this.main.setIcon(); await this.main.refreshBadgeAndMenu(false); this.notificationsService.updateConnection(msg.command === 'unlocked'); this.systemService.cancelProcessReload(); - - if (this.lockedVaultPendingNotifications.length > 0) { - const retryItem = this.lockedVaultPendingNotifications.pop(); - await this.processMessage(retryItem.msg, retryItem.sender, null); - - await BrowserApi.closeLoginTab(); - - if (retryItem?.sender?.tab?.id) { - await BrowserApi.focusSpecifiedTab(retryItem.sender.tab.id); - } - } break; case 'addToLockedVaultPendingNotifications': const retryMessage = { From ca0fe76172499c25d0f88111710d859af57e4f76 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 15 Oct 2021 15:28:10 +0200 Subject: [PATCH 04/17] Move routing of actions after unlock into main.background As we are unable to send a message from one background script to another, I moved the routing of the retryAction into main.background and call processMessages on the notificationBackground in unlockCompleted --- src/background/main.background.ts | 16 ++++++++++++++++ src/background/runtime.background.ts | 21 ++++++++++++--------- src/notification/bar.js | 2 ++ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/background/main.background.ts b/src/background/main.background.ts index e2ded7cbc07..0182b8f1b3e 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -127,6 +127,7 @@ export default class MainBackground { onUpdatedRan: boolean; onReplacedRan: boolean; loginToAutoFill: any = null; + lockedVaultPendingNotifications: { commandToRetry: any, from: string }[] = []; private commandsBackground: CommandsBackground; private contextMenusBackground: ContextMenusBackground; @@ -341,6 +342,21 @@ export default class MainBackground { } } + async unlockCompleted() { + if (this.lockedVaultPendingNotifications.length === 0) { + return; + } + + const lockedVaultPendingNotificationsItem = this.lockedVaultPendingNotifications.pop(); + switch (lockedVaultPendingNotificationsItem.from) { + case 'notificationBar': + await this.notificationBackground.processMessage(lockedVaultPendingNotificationsItem.commandToRetry, lockedVaultPendingNotificationsItem.commandToRetry.sender, null); + break; + default: + break; + } + } + async logout(expired: boolean) { await this.eventService.uploadEvents(); const userId = await this.userService.getUserId(); diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index 44919c9c74a..142f6d0973d 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -25,8 +25,6 @@ export default class RuntimeBackground { private pageDetailsToAutoFill: any[] = []; private onInstalledReason: string = null; - private lockedVaultPendingNotifications: any[] = []; - constructor(private main: MainBackground, private autofillService: AutofillService, private platformUtilsService: BrowserPlatformUtilsService, private storageService: StorageService, private i18nService: I18nService, @@ -54,26 +52,31 @@ export default class RuntimeBackground { switch (msg.command) { case 'loggedIn': case 'unlocked': - if (this.lockedVaultPendingNotifications.length > 0) { + if (this.main.lockedVaultPendingNotifications.length > 0) { await BrowserApi.closeLoginTab(); - if (item?.sender?.tab?.id) { - await BrowserApi.focusSpecifiedTab(item.sender.tab.id); + const item = this.main.lockedVaultPendingNotifications[0]; + if (item.commandToRetry?.sender?.tab?.id) { + await BrowserApi.focusSpecifiedTab(item.commandToRetry.sender.tab.id); } - await this.processMessage(item.msg, item.sender, null); } await this.main.setIcon(); await this.main.refreshBadgeAndMenu(false); this.notificationsService.updateConnection(msg.command === 'unlocked'); this.systemService.cancelProcessReload(); + + this.main.unlockCompleted(); break; case 'addToLockedVaultPendingNotifications': const retryMessage = { - msg: msg.retryItem, - sender: sender, + commandToRetry: { + ...msg.retryItem, + sender: sender + }, + from: msg.from, }; - this.lockedVaultPendingNotifications.push(retryMessage); + this.main.lockedVaultPendingNotifications.push(retryMessage); break; case 'logout': await this.main.logout(msg.expired); diff --git a/src/notification/bar.js b/src/notification/bar.js index 4cad508a057..d5590a31152 100644 --- a/src/notification/bar.js +++ b/src/notification/bar.js @@ -78,6 +78,7 @@ document.addEventListener('DOMContentLoaded', () => { sendPlatformMessage({ command: 'addToLockedVaultPendingNotifications', + from: 'notificationBar', retryItem: bgAddSaveMessage }); return; @@ -122,6 +123,7 @@ document.addEventListener('DOMContentLoaded', () => { sendPlatformMessage({ command: 'addToLockedVaultPendingNotifications', + from: 'notificationBar', retryItem: bgChangeSaveMessage, }); return; From 79f849fd9272410abf092481416d7ae347ba02a5 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 15 Oct 2021 15:32:56 +0200 Subject: [PATCH 05/17] Make linter happy --- src/background/notification.background.ts | 93 +++++++++++------------ src/background/runtime.background.ts | 9 +-- 2 files changed, 47 insertions(+), 55 deletions(-) diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index 12ded645c6b..b92b58e245c 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -45,6 +45,52 @@ export default class NotificationBackground { this.cleanupNotificationQueue(); } + async processMessage(msg: any, sender: any, sendResponse: any) { + switch (msg.command) { + case 'bgGetDataForTab': + await this.getDataForTab(sender.tab, msg.responseCommand); + break; + case 'bgCloseNotificationBar': + await BrowserApi.tabSendMessageData(sender.tab, 'closeNotificationBar'); + break; + case 'bgAdjustNotificationBar': + await BrowserApi.tabSendMessageData(sender.tab, 'adjustNotificationBar', msg.data); + break; + case 'bgAddLogin': + await this.addLogin(msg.login, sender.tab); + break; + case 'bgChangedPassword': + await this.changedPassword(msg.data, sender.tab); + break; + case 'bgAddClose': + case 'bgChangeClose': + this.removeTabFromNotificationQueue(sender.tab); + break; + case 'bgAddSave': + case 'bgChangeSave': + await this.saveOrUpdateCredentials(sender.tab, msg.folder); + break; + case 'bgNeverSave': + await this.saveNever(sender.tab); + break; + case 'collectPageDetailsResponse': + switch (msg.sender) { + case 'notificationBar': + const forms = this.autofillService.getFormsWithPasswordFields(msg.details); + await BrowserApi.tabSendMessageData(msg.tab, 'notificationBarPageDetails', { + details: msg.details, + forms: forms, + }); + break; + default: + break; + } + break; + default: + break; + } + } + async checkNotificationQueue(tab: any = null): Promise { if (this.notificationQueue.length === 0) { return; @@ -112,53 +158,6 @@ export default class NotificationBackground { } } - async processMessage(msg: any, sender: any, sendResponse: any) { - switch (msg.command) { - case 'bgGetDataForTab': - await this.getDataForTab(sender.tab, msg.responseCommand); - break; - case 'bgCloseNotificationBar': - await BrowserApi.tabSendMessageData(sender.tab, 'closeNotificationBar'); - break; - case 'bgAdjustNotificationBar': - await BrowserApi.tabSendMessageData(sender.tab, 'adjustNotificationBar', msg.data); - break; - case 'bgAddLogin': - await this.addLogin(msg.login, sender.tab); - break; - case 'bgChangedPassword': - await this.changedPassword(msg.data, sender.tab); - break; - case 'bgAddClose': - case 'bgChangeClose': - this.removeTabFromNotificationQueue(sender.tab); - break; - case 'bgAddSave': - case 'bgChangeSave': - await this.saveOrUpdateCredentials(sender.tab, msg.folder); - break; - case 'bgNeverSave': - await this.saveNever(sender.tab); - break; - case 'collectPageDetailsResponse': - switch (msg.sender) { - case 'notificationBar': - console.log('collectPageDetailsResponse for notificationBar received', msg.tab) - const forms = this.autofillService.getFormsWithPasswordFields(msg.details); - await BrowserApi.tabSendMessageData(msg.tab, 'notificationBarPageDetails', { - details: msg.details, - forms: forms, - }); - break; - default: - break; - } - break; - default: - break; - } - } - private async addLogin(loginInfo: any, tab: any) { const loginDomain = Utils.getDomain(loginInfo.url); if (loginDomain == null) { diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index 142f6d0973d..4086a957409 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -13,14 +13,7 @@ import { BrowserApi } from '../browser/browserApi'; import MainBackground from './main.background'; import { Utils } from 'jslib-common/misc/utils'; - -import { PolicyType } from 'jslib-common/enums/policyType'; - -import AddChangePasswordQueueMessage from './models/addChangePasswordQueueMessage'; -import AddLoginQueueMessage from './models/addLoginQueueMessage'; - export default class RuntimeBackground { - private runtime: any; private autofillTimeout: any; private pageDetailsToAutoFill: any[] = []; private onInstalledReason: string = null; @@ -72,7 +65,7 @@ export default class RuntimeBackground { const retryMessage = { commandToRetry: { ...msg.retryItem, - sender: sender + sender: sender, }, from: msg.from, }; From f951c860ea2343a619b977197b4cf0bf7163f251 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 15 Oct 2021 15:35:31 +0200 Subject: [PATCH 06/17] Shorten variable name --- src/background/main.background.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 0182b8f1b3e..840142d3ee4 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -347,10 +347,10 @@ export default class MainBackground { return; } - const lockedVaultPendingNotificationsItem = this.lockedVaultPendingNotifications.pop(); - switch (lockedVaultPendingNotificationsItem.from) { + const item = this.lockedVaultPendingNotifications.pop(); + switch (item.from) { case 'notificationBar': - await this.notificationBackground.processMessage(lockedVaultPendingNotificationsItem.commandToRetry, lockedVaultPendingNotificationsItem.commandToRetry.sender, null); + await this.notificationBackground.processMessage(item.commandToRetry, item.commandToRetry.sender, null); break; default: break; From d1977f1f08c9ad05cef18de7761ae413c949e793 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 15 Oct 2021 19:42:05 +0200 Subject: [PATCH 07/17] Added type declarations where chrome.tabs.Tab applies --- src/background/notification.background.ts | 20 ++++++++++---------- src/browser/browserApi.ts | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index b92b58e245c..d11e8e72e21 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -91,7 +91,7 @@ export default class NotificationBackground { } } - async checkNotificationQueue(tab: any = null): Promise { + async checkNotificationQueue(tab: chrome.tabs.Tab = null): Promise { if (this.notificationQueue.length === 0) { return; } @@ -116,7 +116,7 @@ export default class NotificationBackground { setTimeout(() => this.cleanupNotificationQueue(), 2 * 60 * 1000); // check every 2 minutes } - private doNotificationQueueCheck(tab: any) { + private doNotificationQueueCheck(tab: chrome.tabs.Tab): void { if (tab == null) { return; } @@ -150,7 +150,7 @@ export default class NotificationBackground { } } - private removeTabFromNotificationQueue(tab: any) { + private removeTabFromNotificationQueue(tab: chrome.tabs.Tab) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) { if (this.notificationQueue[i].tabId === tab.id) { this.notificationQueue.splice(i, 1); @@ -158,7 +158,7 @@ export default class NotificationBackground { } } - private async addLogin(loginInfo: any, tab: any) { + private async addLogin(loginInfo: any, tab: chrome.tabs.Tab) { const loginDomain = Utils.getDomain(loginInfo.url); if (loginDomain == null) { return; @@ -200,7 +200,7 @@ export default class NotificationBackground { } } - private async pushAddLoginToQueue(loginDomain: string, loginInfo: any, tab: any, isVaultLocked: boolean = false) { + private async pushAddLoginToQueue(loginDomain: string, loginInfo: any, tab: chrome.tabs.Tab, isVaultLocked: boolean = false) { // remove any old messages for this tab this.removeTabFromNotificationQueue(tab); const message: AddLoginQueueMessage = { @@ -217,7 +217,7 @@ export default class NotificationBackground { await this.checkNotificationQueue(tab); } - private async changedPassword(changeData: any, tab: any) { + private async changedPassword(changeData: any, tab: chrome.tabs.Tab) { const loginDomain = Utils.getDomain(changeData.url); if (loginDomain == null) { return; @@ -243,7 +243,7 @@ export default class NotificationBackground { } } - private async pushChangePasswordToQueue(cipherId: string, loginDomain: string, newPassword: string, tab: any, isVaultLocked: boolean = false) { + private async pushChangePasswordToQueue(cipherId: string, loginDomain: string, newPassword: string, tab: chrome.tabs.Tab, isVaultLocked: boolean = false) { // remove any old messages for this tab this.removeTabFromNotificationQueue(tab); const message: AddChangePasswordQueueMessage = { @@ -259,7 +259,7 @@ export default class NotificationBackground { await this.checkNotificationQueue(tab); } - private async saveOrUpdateCredentials(tab: any, folderId?: string) { + private async saveOrUpdateCredentials(tab: chrome.tabs.Tab, folderId?: string) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) { const queueMessage = this.notificationQueue[i]; if (queueMessage.tabId !== tab.id || @@ -346,7 +346,7 @@ export default class NotificationBackground { } } - private async saveNever(tab: any) { + private async saveNever(tab: chrome.tabs.Tab) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) { const queueMessage = this.notificationQueue[i]; if (queueMessage.tabId !== tab.id || queueMessage.type !== 'addLogin') { @@ -366,7 +366,7 @@ export default class NotificationBackground { } } - private async getDataForTab(tab: any, responseCommand: string) { + private async getDataForTab(tab: chrome.tabs.Tab, responseCommand: string) { const responseData: any = {}; if (responseCommand === 'notificationBarGetFoldersList') { responseData.folders = await this.folderService.getAllDecrypted(); diff --git a/src/browser/browserApi.ts b/src/browser/browserApi.ts index 648394c9bdc..7ccc549e371 100644 --- a/src/browser/browserApi.ts +++ b/src/browser/browserApi.ts @@ -48,7 +48,7 @@ export class BrowserApi { return null; } - static tabSendMessageData(tab: any, command: string, data: any = null): Promise { + static tabSendMessageData(tab: chrome.tabs.Tab, command: string, data: any = null): Promise { const obj: any = { command: command, }; @@ -60,7 +60,7 @@ export class BrowserApi { return BrowserApi.tabSendMessage(tab, obj); } - static async tabSendMessage(tab: any, obj: any, options: any = null): Promise { + static async tabSendMessage(tab: chrome.tabs.Tab, obj: any, options: chrome.tabs.MessageSendOptions = null): Promise { if (!tab || !tab.id) { return; } From 92459c60986db01da61f5da2601437ad10b4c4ab Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 15 Oct 2021 19:47:48 +0200 Subject: [PATCH 08/17] Declare and use types for notificationQueue --- .../models/addChangePasswordQueueMessage.ts | 9 +++----- src/background/models/addLoginQueueMessage.ts | 9 +++----- .../models/notificationQueueMessage.ts | 9 ++++++++ .../models/notificationQueueMessageType.ts | 4 ++++ src/background/notification.background.ts | 21 ++++++++++--------- 5 files changed, 30 insertions(+), 22 deletions(-) create mode 100644 src/background/models/notificationQueueMessage.ts create mode 100644 src/background/models/notificationQueueMessageType.ts diff --git a/src/background/models/addChangePasswordQueueMessage.ts b/src/background/models/addChangePasswordQueueMessage.ts index ad1efe3da33..9adcc3d5e74 100644 --- a/src/background/models/addChangePasswordQueueMessage.ts +++ b/src/background/models/addChangePasswordQueueMessage.ts @@ -1,9 +1,6 @@ -export default class AddChangePasswordQueueMessage { - type: string; +import NotificationQueueMessage from "./notificationQueueMessage"; + +export default class AddChangePasswordQueueMessage extends NotificationQueueMessage { cipherId: string; newPassword: string; - domain: string; - tabId: string; - expires: Date; - wasVaultLocked: boolean; } diff --git a/src/background/models/addLoginQueueMessage.ts b/src/background/models/addLoginQueueMessage.ts index 246dca03a4c..466c5c6c95e 100644 --- a/src/background/models/addLoginQueueMessage.ts +++ b/src/background/models/addLoginQueueMessage.ts @@ -1,10 +1,7 @@ -export default class AddLoginQueueMessage { - type: string; +import NotificationQueueMessage from "./notificationQueueMessage"; + +export default class AddLoginQueueMessage extends NotificationQueueMessage { username: string; password: string; - domain: string; uri: string; - tabId: string; - expires: Date; - wasVaultLocked: boolean; } diff --git a/src/background/models/notificationQueueMessage.ts b/src/background/models/notificationQueueMessage.ts new file mode 100644 index 00000000000..9c031af0292 --- /dev/null +++ b/src/background/models/notificationQueueMessage.ts @@ -0,0 +1,9 @@ +import { NotificationQueueMessageType } from "./NotificationQueueMessageType"; + +export default class NotificationQueueMessage { + type: NotificationQueueMessageType; + domain: string; + tabId: number; + expires: Date; + wasVaultLocked: boolean; +} diff --git a/src/background/models/notificationQueueMessageType.ts b/src/background/models/notificationQueueMessageType.ts new file mode 100644 index 00000000000..5c27572dacd --- /dev/null +++ b/src/background/models/notificationQueueMessageType.ts @@ -0,0 +1,4 @@ +export enum NotificationQueueMessageType { + addLogin = 'addLogin', + changePassword = 'changePassword', +} diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index d11e8e72e21..49ab35e3cb2 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -22,10 +22,11 @@ import { PolicyType } from 'jslib-common/enums/policyType'; import AddChangePasswordQueueMessage from './models/addChangePasswordQueueMessage'; import AddLoginQueueMessage from './models/addLoginQueueMessage'; +import { NotificationQueueMessageType } from './models/NotificationQueueMessageType'; export default class NotificationBackground { - private notificationQueue: any[] = []; + private notificationQueue: (AddLoginQueueMessage | AddChangePasswordQueueMessage)[] = []; constructor(private main: MainBackground, private autofillService: AutofillService, private cipherService: CipherService, private storageService: StorageService, @@ -131,14 +132,14 @@ export default class NotificationBackground { continue; } - if (this.notificationQueue[i].type === 'addLogin') { + if (this.notificationQueue[i].type === NotificationQueueMessageType.addLogin) { BrowserApi.tabSendMessageData(tab, 'openNotificationBar', { type: 'add', typeData: { isVaultLocked: this.notificationQueue[i].wasVaultLocked, }, }); - } else if (this.notificationQueue[i].type === 'changePassword') { + } else if (this.notificationQueue[i].type === NotificationQueueMessageType.changePassword) { BrowserApi.tabSendMessageData(tab, 'openNotificationBar', { type: 'change', typeData: { @@ -204,7 +205,7 @@ export default class NotificationBackground { // remove any old messages for this tab this.removeTabFromNotificationQueue(tab); const message: AddLoginQueueMessage = { - type: 'addLogin', + type: NotificationQueueMessageType.addLogin, username: loginInfo.username, password: loginInfo.password, domain: loginDomain, @@ -247,7 +248,7 @@ export default class NotificationBackground { // remove any old messages for this tab this.removeTabFromNotificationQueue(tab); const message: AddChangePasswordQueueMessage = { - type: 'changePassword', + type: NotificationQueueMessageType.changePassword, cipherId: cipherId, newPassword: newPassword, domain: loginDomain, @@ -263,7 +264,7 @@ export default class NotificationBackground { for (let i = this.notificationQueue.length - 1; i >= 0; i--) { const queueMessage = this.notificationQueue[i]; if (queueMessage.tabId !== tab.id || - (queueMessage.type !== 'addLogin' && queueMessage.type !== 'changePassword')) { + (queueMessage.type !== NotificationQueueMessageType.addLogin && queueMessage.type !== NotificationQueueMessageType.changePassword)) { continue; } @@ -275,7 +276,7 @@ export default class NotificationBackground { this.notificationQueue.splice(i, 1); BrowserApi.tabSendMessageData(tab, 'closeNotificationBar'); - if (queueMessage.type === 'changePassword') { + if (queueMessage.type === NotificationQueueMessageType.changePassword) { const message = (queueMessage as AddChangePasswordQueueMessage); const cipher = await this.getDecryptedCipherById(message.cipherId); if (cipher == null) { @@ -286,11 +287,11 @@ export default class NotificationBackground { } if (!queueMessage.wasVaultLocked) { - await this.createNewCipher(queueMessage, folderId); + await this.createNewCipher(queueMessage as AddLoginQueueMessage, folderId); } // If the vault was locked, check if a cipher needs updating instead of creating a new one - if (queueMessage.type === 'addLogin' && queueMessage.wasVaultLocked === true) { + if (queueMessage.type === NotificationQueueMessageType.addLogin && queueMessage.wasVaultLocked === true) { const message = (queueMessage as AddLoginQueueMessage); const ciphers = await this.cipherService.getAllDecryptedForUrl(message.uri); const usernameMatches = ciphers.filter(c => c.login.username != null && @@ -349,7 +350,7 @@ export default class NotificationBackground { private async saveNever(tab: chrome.tabs.Tab) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) { const queueMessage = this.notificationQueue[i]; - if (queueMessage.tabId !== tab.id || queueMessage.type !== 'addLogin') { + if (queueMessage.tabId !== tab.id || queueMessage.type !== NotificationQueueMessageType.addLogin) { continue; } From 4b49b1fcc00f1de2af3c992832f6ba7a81699d5c Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Mon, 18 Oct 2021 15:32:38 +0200 Subject: [PATCH 09/17] Add type CipherView for AutoFill functionality --- src/background/contextMenus.background.ts | 3 ++- src/background/main.background.ts | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/background/contextMenus.background.ts b/src/background/contextMenus.background.ts index b0fa7097d2a..e46fe8e3694 100644 --- a/src/background/contextMenus.background.ts +++ b/src/background/contextMenus.background.ts @@ -10,6 +10,7 @@ import { TotpService } from 'jslib-common/abstractions/totp.service'; import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service'; import { EventType } from 'jslib-common/enums/eventType'; +import { CipherView } from 'jslib-common/models/view/cipherView'; export default class ContextMenusBackground { private contextMenus: any; @@ -88,7 +89,7 @@ export default class ContextMenusBackground { } } - private async startAutofillPage(cipher: any) { + private async startAutofillPage(cipher: CipherView) { this.main.loginToAutoFill = cipher; const tab = await BrowserApi.getTabFromCurrentWindow(); if (tab == null) { diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 840142d3ee4..880ab228623 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -1,6 +1,8 @@ import { CipherRepromptType } from 'jslib-common/enums/cipherRepromptType'; import { CipherType } from 'jslib-common/enums/cipherType'; +import { CipherView } from 'jslib-common/models/view/cipherView'; + import { ApiService } from 'jslib-common/services/api.service'; import { AppIdService } from 'jslib-common/services/appId.service'; import { AuditService } from 'jslib-common/services/audit.service'; @@ -126,7 +128,7 @@ export default class MainBackground { onUpdatedRan: boolean; onReplacedRan: boolean; - loginToAutoFill: any = null; + loginToAutoFill: CipherView = null; lockedVaultPendingNotifications: { commandToRetry: any, from: string }[] = []; private commandsBackground: CommandsBackground; From 1bf7a7cad6b53ab3f7c12f6eb02646031de7f49a Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Mon, 18 Oct 2021 16:31:59 +0200 Subject: [PATCH 10/17] Perform null check on chrome.runtime --- src/background/notification.background.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index 49ab35e3cb2..c58f2426904 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -35,7 +35,7 @@ export default class NotificationBackground { } async init() { - if (!chrome.runtime) { + if (chrome.runtime == null) { return; } From 2699e0f5a0742ef37bedf6d90ebd32b3eae5408d Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Mon, 18 Oct 2021 16:34:14 +0200 Subject: [PATCH 11/17] Add types for common browser functions --- src/background/notification.background.ts | 6 +++--- src/background/runtime.background.ts | 2 +- src/browser/browserApi.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index c58f2426904..580248a049b 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -39,14 +39,14 @@ export default class NotificationBackground { return; } - BrowserApi.messageListener('notification.background', async (msg: any, sender: any, sendResponse: any) => { - await this.processMessage(msg, sender, sendResponse); + BrowserApi.messageListener('notification.background', async (msg: any, sender: chrome.runtime.MessageSender) => { + await this.processMessage(msg, sender); }); this.cleanupNotificationQueue(); } - async processMessage(msg: any, sender: any, sendResponse: any) { + async processMessage(msg: any, sender: chrome.runtime.MessageSender) { switch (msg.command) { case 'bgGetDataForTab': await this.getDataForTab(sender.tab, msg.responseCommand); diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index 4086a957409..e57073e1d39 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -36,7 +36,7 @@ export default class RuntimeBackground { } await this.checkOnInstalled(); - BrowserApi.messageListener('runtime.background', async (msg: any, sender: any, sendResponse: any) => { + BrowserApi.messageListener('runtime.background', async (msg: any, sender: chrome.runtime.MessageSender, sendResponse: any) => { await this.processMessage(msg, sender, sendResponse); }); } diff --git a/src/browser/browserApi.ts b/src/browser/browserApi.ts index 7ccc549e371..5efb4bc8217 100644 --- a/src/browser/browserApi.ts +++ b/src/browser/browserApi.ts @@ -91,8 +91,8 @@ export class BrowserApi { chrome.tabs.create({ url: url, active: active }); } - static messageListener(name: string, callback: (message: any, sender: any, response: any) => void) { - chrome.runtime.onMessage.addListener((msg: any, sender: any, response: any) => { + static messageListener(name: string, callback: (message: any, sender: chrome.runtime.MessageSender, response: any) => void) { + chrome.runtime.onMessage.addListener((msg: any, sender: chrome.runtime.MessageSender, response: any) => { callback(msg, sender, response); }); } From fd8de4ca0c1e054f0c3d9e2426ce8717441468c5 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Mon, 18 Oct 2021 16:41:42 +0200 Subject: [PATCH 12/17] Use messages/events instead of main.unlockCompleted --- src/background/main.background.ts | 18 +------------- .../lockedVaultPendingNotificationsItem.ts | 7 ++++++ src/background/notification.background.ts | 6 +++++ src/background/runtime.background.ts | 24 +++++++++---------- src/content/message_handler.ts | 7 ++++++ 5 files changed, 33 insertions(+), 29 deletions(-) create mode 100644 src/background/models/lockedVaultPendingNotificationsItem.ts diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 880ab228623..486ef98b3c2 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -129,16 +129,15 @@ export default class MainBackground { onUpdatedRan: boolean; onReplacedRan: boolean; loginToAutoFill: CipherView = null; - lockedVaultPendingNotifications: { commandToRetry: any, from: string }[] = []; private commandsBackground: CommandsBackground; private contextMenusBackground: ContextMenusBackground; private idleBackground: IdleBackground; + private notificationBackground: NotificationBackground; private runtimeBackground: RuntimeBackground; private tabsBackground: TabsBackground; private webRequestBackground: WebRequestBackground; private windowsBackground: WindowsBackground; - private notificationBackground: NotificationBackground; private sidebarAction: any; private buildingContextMenu: boolean; @@ -344,21 +343,6 @@ export default class MainBackground { } } - async unlockCompleted() { - if (this.lockedVaultPendingNotifications.length === 0) { - return; - } - - const item = this.lockedVaultPendingNotifications.pop(); - switch (item.from) { - case 'notificationBar': - await this.notificationBackground.processMessage(item.commandToRetry, item.commandToRetry.sender, null); - break; - default: - break; - } - } - async logout(expired: boolean) { await this.eventService.uploadEvents(); const userId = await this.userService.getUserId(); diff --git a/src/background/models/lockedVaultPendingNotificationsItem.ts b/src/background/models/lockedVaultPendingNotificationsItem.ts new file mode 100644 index 00000000000..df2f2eb7aa5 --- /dev/null +++ b/src/background/models/lockedVaultPendingNotificationsItem.ts @@ -0,0 +1,7 @@ +export default class lockedVaultPendingNotificationsItem { + commandToRetry: { + msg: any; + sender: chrome.runtime.MessageSender; + } + target: string; +} diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index 580248a049b..58d2a048789 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -48,6 +48,12 @@ export default class NotificationBackground { async processMessage(msg: any, sender: chrome.runtime.MessageSender) { switch (msg.command) { + case 'unlockCompleted': + if (msg.data.target !== 'notification.background') { + return; + } + await this.processMessage(msg.data.commandToRetry.msg, msg.data.commandToRetry.sender); + break; case 'bgGetDataForTab': await this.getDataForTab(sender.tab, msg.responseCommand); break; diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index e57073e1d39..93782ae3629 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -13,10 +13,13 @@ import { BrowserApi } from '../browser/browserApi'; import MainBackground from './main.background'; import { Utils } from 'jslib-common/misc/utils'; +import lockedVaultPendingNotificationsItem from './models/lockedVaultPendingNotificationsItem'; + export default class RuntimeBackground { private autofillTimeout: any; private pageDetailsToAutoFill: any[] = []; private onInstalledReason: string = null; + private lockedVaultPendingNotifications: lockedVaultPendingNotificationsItem[] = []; constructor(private main: MainBackground, private autofillService: AutofillService, private platformUtilsService: BrowserPlatformUtilsService, @@ -45,11 +48,13 @@ export default class RuntimeBackground { switch (msg.command) { case 'loggedIn': case 'unlocked': - if (this.main.lockedVaultPendingNotifications.length > 0) { + let item: lockedVaultPendingNotificationsItem; + + if (this.lockedVaultPendingNotifications.length > 0) { await BrowserApi.closeLoginTab(); - const item = this.main.lockedVaultPendingNotifications[0]; - if (item.commandToRetry?.sender?.tab?.id) { + item = this.lockedVaultPendingNotifications.pop(); + if (item.commandToRetry.sender?.tab?.id) { await BrowserApi.focusSpecifiedTab(item.commandToRetry.sender.tab.id); } } @@ -59,17 +64,12 @@ export default class RuntimeBackground { this.notificationsService.updateConnection(msg.command === 'unlocked'); this.systemService.cancelProcessReload(); - this.main.unlockCompleted(); + if (item) { + await BrowserApi.tabSendMessageData(item.commandToRetry.sender.tab, 'unlockCompleted', item); + } break; case 'addToLockedVaultPendingNotifications': - const retryMessage = { - commandToRetry: { - ...msg.retryItem, - sender: sender, - }, - from: msg.from, - }; - this.main.lockedVaultPendingNotifications.push(retryMessage); + this.lockedVaultPendingNotifications.push(msg.data); break; case 'logout': await this.main.logout(msg.expired); diff --git a/src/content/message_handler.ts b/src/content/message_handler.ts index 4358a97945c..688553db7d6 100644 --- a/src/content/message_handler.ts +++ b/src/content/message_handler.ts @@ -20,3 +20,10 @@ window.addEventListener('message', event => { }); } }, false); + +chrome.runtime.onMessage.addListener(event => { + + if (event.command === 'unlockCompleted') { + chrome.runtime.sendMessage(event); + } +}); From 95e938731428725e50d02fb366942dc9939f0b32 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Mon, 18 Oct 2021 16:42:32 +0200 Subject: [PATCH 13/17] Remove logic out of notification content scripts --- src/background/notification.background.ts | 13 +++++++++++ src/content/message_handler.ts | 7 ++++++ src/notification/bar.js | 27 ----------------------- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index 58d2a048789..287f7437f60 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -23,6 +23,7 @@ import { PolicyType } from 'jslib-common/enums/policyType'; import AddChangePasswordQueueMessage from './models/addChangePasswordQueueMessage'; import AddLoginQueueMessage from './models/addLoginQueueMessage'; import { NotificationQueueMessageType } from './models/NotificationQueueMessageType'; +import lockedVaultPendingNotificationsItem from './models/lockedVaultPendingNotificationsItem'; export default class NotificationBackground { @@ -75,6 +76,18 @@ export default class NotificationBackground { break; case 'bgAddSave': case 'bgChangeSave': + if (await this.vaultTimeoutService.isLocked()) { + const retryMessage: lockedVaultPendingNotificationsItem = { + commandToRetry: { + msg: msg, + sender: sender, + }, + target: 'notification.background', + }; + await BrowserApi.tabSendMessageData(sender.tab, 'addToLockedVaultPendingNotifications', retryMessage); + await BrowserApi.tabSendMessageData(sender.tab, 'promptForLogin'); + return; + } await this.saveOrUpdateCredentials(sender.tab, msg.folder); break; case 'bgNeverSave': diff --git a/src/content/message_handler.ts b/src/content/message_handler.ts index 688553db7d6..361e434fd72 100644 --- a/src/content/message_handler.ts +++ b/src/content/message_handler.ts @@ -22,6 +22,13 @@ window.addEventListener('message', event => { }, false); chrome.runtime.onMessage.addListener(event => { + if (event.command === 'promptForLogin') { + chrome.runtime.sendMessage(event); + } + + if (event.command === 'addToLockedVaultPendingNotifications') { + chrome.runtime.sendMessage(event); + } if (event.command === 'unlockCompleted') { chrome.runtime.sendMessage(event); diff --git a/src/notification/bar.js b/src/notification/bar.js index d5590a31152..fec7ed16f45 100644 --- a/src/notification/bar.js +++ b/src/notification/bar.js @@ -70,20 +70,6 @@ document.addEventListener('DOMContentLoaded', () => { command: 'bgAddSave', folder: folderId, }; - - if (isVaultLocked) { - sendPlatformMessage({ - command: 'promptForLogin' - }); - - sendPlatformMessage({ - command: 'addToLockedVaultPendingNotifications', - from: 'notificationBar', - retryItem: bgAddSaveMessage - }); - return; - } - sendPlatformMessage(bgAddSaveMessage); }); @@ -115,19 +101,6 @@ document.addEventListener('DOMContentLoaded', () => { const bgChangeSaveMessage = { command: 'bgChangeSave' }; - - if (isVaultLocked) { - sendPlatformMessage({ - command: 'promptForLogin' - }); - - sendPlatformMessage({ - command: 'addToLockedVaultPendingNotifications', - from: 'notificationBar', - retryItem: bgChangeSaveMessage, - }); - return; - } sendPlatformMessage(bgChangeSaveMessage); }); } From 2299abe7a688ab47d524f3305c2448fa37d3604e Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Mon, 18 Oct 2021 16:47:14 +0200 Subject: [PATCH 14/17] Make linter happy --- src/background/notification.background.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index 287f7437f60..25a39a39b49 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -22,8 +22,8 @@ import { PolicyType } from 'jslib-common/enums/policyType'; import AddChangePasswordQueueMessage from './models/addChangePasswordQueueMessage'; import AddLoginQueueMessage from './models/addLoginQueueMessage'; -import { NotificationQueueMessageType } from './models/NotificationQueueMessageType'; import lockedVaultPendingNotificationsItem from './models/lockedVaultPendingNotificationsItem'; +import { NotificationQueueMessageType } from './models/NotificationQueueMessageType'; export default class NotificationBackground { From d4e91a81f9b1fc64a91295b62ebddeb8b1718790 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Tue, 19 Oct 2021 11:20:55 +0200 Subject: [PATCH 15/17] Capitalize class name: LockedVaultPendingNotificationsItem --- .../models/lockedVaultPendingNotificationsItem.ts | 2 +- src/background/notification.background.ts | 4 ++-- src/background/runtime.background.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/background/models/lockedVaultPendingNotificationsItem.ts b/src/background/models/lockedVaultPendingNotificationsItem.ts index df2f2eb7aa5..dec23139662 100644 --- a/src/background/models/lockedVaultPendingNotificationsItem.ts +++ b/src/background/models/lockedVaultPendingNotificationsItem.ts @@ -1,4 +1,4 @@ -export default class lockedVaultPendingNotificationsItem { +export default class LockedVaultPendingNotificationsItem { commandToRetry: { msg: any; sender: chrome.runtime.MessageSender; diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index 25a39a39b49..d12834e0a42 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -22,7 +22,7 @@ import { PolicyType } from 'jslib-common/enums/policyType'; import AddChangePasswordQueueMessage from './models/addChangePasswordQueueMessage'; import AddLoginQueueMessage from './models/addLoginQueueMessage'; -import lockedVaultPendingNotificationsItem from './models/lockedVaultPendingNotificationsItem'; +import LockedVaultPendingNotificationsItem from './models/lockedVaultPendingNotificationsItem'; import { NotificationQueueMessageType } from './models/NotificationQueueMessageType'; export default class NotificationBackground { @@ -77,7 +77,7 @@ export default class NotificationBackground { case 'bgAddSave': case 'bgChangeSave': if (await this.vaultTimeoutService.isLocked()) { - const retryMessage: lockedVaultPendingNotificationsItem = { + const retryMessage: LockedVaultPendingNotificationsItem = { commandToRetry: { msg: msg, sender: sender, diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index 93782ae3629..71dbe6ec9d5 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -13,13 +13,13 @@ import { BrowserApi } from '../browser/browserApi'; import MainBackground from './main.background'; import { Utils } from 'jslib-common/misc/utils'; -import lockedVaultPendingNotificationsItem from './models/lockedVaultPendingNotificationsItem'; +import LockedVaultPendingNotificationsItem from './models/lockedVaultPendingNotificationsItem'; export default class RuntimeBackground { private autofillTimeout: any; private pageDetailsToAutoFill: any[] = []; private onInstalledReason: string = null; - private lockedVaultPendingNotifications: lockedVaultPendingNotificationsItem[] = []; + private lockedVaultPendingNotifications: LockedVaultPendingNotificationsItem[] = []; constructor(private main: MainBackground, private autofillService: AutofillService, private platformUtilsService: BrowserPlatformUtilsService, @@ -48,7 +48,7 @@ export default class RuntimeBackground { switch (msg.command) { case 'loggedIn': case 'unlocked': - let item: lockedVaultPendingNotificationsItem; + let item: LockedVaultPendingNotificationsItem; if (this.lockedVaultPendingNotifications.length > 0) { await BrowserApi.closeLoginTab(); From 344878ef4f0f8999424a340718372646e6f2815e Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Tue, 19 Oct 2021 11:47:25 +0200 Subject: [PATCH 16/17] Simplify forwarding tab messages to runtime --- src/content/message_handler.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/content/message_handler.ts b/src/content/message_handler.ts index 361e434fd72..e10834a3d6d 100644 --- a/src/content/message_handler.ts +++ b/src/content/message_handler.ts @@ -21,16 +21,10 @@ window.addEventListener('message', event => { } }, false); +const forwardCommands = ['promptForLogin', 'addToLockedVaultPendingNotifications', 'unlockCompleted']; + chrome.runtime.onMessage.addListener(event => { - if (event.command === 'promptForLogin') { - chrome.runtime.sendMessage(event); - } - - if (event.command === 'addToLockedVaultPendingNotifications') { - chrome.runtime.sendMessage(event); - } - - if (event.command === 'unlockCompleted') { + if (forwardCommands.includes(event.command)) { chrome.runtime.sendMessage(event); } }); From 3bb58baf45fe1074429f0dc1886e4278e20cf1db Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Tue, 19 Oct 2021 12:10:31 +0200 Subject: [PATCH 17/17] Add types for addLogin and changePassword runtime messages --- src/background/models/addLoginRuntimeMessage.ts | 5 +++++ .../models/changePasswordRuntimeMessage.ts | 5 +++++ src/background/notification.background.ts | 8 +++++--- src/content/notificationBar.ts | 17 +++++++++++------ 4 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 src/background/models/addLoginRuntimeMessage.ts create mode 100644 src/background/models/changePasswordRuntimeMessage.ts diff --git a/src/background/models/addLoginRuntimeMessage.ts b/src/background/models/addLoginRuntimeMessage.ts new file mode 100644 index 00000000000..3426bc595df --- /dev/null +++ b/src/background/models/addLoginRuntimeMessage.ts @@ -0,0 +1,5 @@ +export default class AddLoginRuntimeMessage { + username: string; + password: string; + url: string; +} diff --git a/src/background/models/changePasswordRuntimeMessage.ts b/src/background/models/changePasswordRuntimeMessage.ts new file mode 100644 index 00000000000..8f3f6aa5778 --- /dev/null +++ b/src/background/models/changePasswordRuntimeMessage.ts @@ -0,0 +1,5 @@ +export default class ChangePasswordRuntimeMessage { + currentPassword: string; + newPassword: string; + url: string; +} diff --git a/src/background/notification.background.ts b/src/background/notification.background.ts index d12834e0a42..929da3f040d 100644 --- a/src/background/notification.background.ts +++ b/src/background/notification.background.ts @@ -22,6 +22,8 @@ import { PolicyType } from 'jslib-common/enums/policyType'; import AddChangePasswordQueueMessage from './models/addChangePasswordQueueMessage'; import AddLoginQueueMessage from './models/addLoginQueueMessage'; +import AddLoginRuntimeMessage from './models/addLoginRuntimeMessage'; +import ChangePasswordRuntimeMessage from './models/changePasswordRuntimeMessage'; import LockedVaultPendingNotificationsItem from './models/lockedVaultPendingNotificationsItem'; import { NotificationQueueMessageType } from './models/NotificationQueueMessageType'; @@ -178,7 +180,7 @@ export default class NotificationBackground { } } - private async addLogin(loginInfo: any, tab: chrome.tabs.Tab) { + private async addLogin(loginInfo: AddLoginRuntimeMessage, tab: chrome.tabs.Tab) { const loginDomain = Utils.getDomain(loginInfo.url); if (loginDomain == null) { return; @@ -220,7 +222,7 @@ export default class NotificationBackground { } } - private async pushAddLoginToQueue(loginDomain: string, loginInfo: any, tab: chrome.tabs.Tab, isVaultLocked: boolean = false) { + private async pushAddLoginToQueue(loginDomain: string, loginInfo: AddLoginRuntimeMessage, tab: chrome.tabs.Tab, isVaultLocked: boolean = false) { // remove any old messages for this tab this.removeTabFromNotificationQueue(tab); const message: AddLoginQueueMessage = { @@ -237,7 +239,7 @@ export default class NotificationBackground { await this.checkNotificationQueue(tab); } - private async changedPassword(changeData: any, tab: chrome.tabs.Tab) { + private async changedPassword(changeData: ChangePasswordRuntimeMessage, tab: chrome.tabs.Tab) { const loginDomain = Utils.getDomain(changeData.url); if (loginDomain == null) { return; diff --git a/src/content/notificationBar.ts b/src/content/notificationBar.ts index 103b819d6e3..da3f25d7d46 100644 --- a/src/content/notificationBar.ts +++ b/src/content/notificationBar.ts @@ -1,3 +1,6 @@ +import AddLoginRuntimeMessage from 'src/background/models/addLoginRuntimeMessage'; +import ChangePasswordRuntimeMessage from 'src/background/models/changePasswordRuntimeMessage'; + document.addEventListener('DOMContentLoaded', event => { if (window.location.hostname.indexOf('vault.bitwarden.com') > -1) { return; @@ -294,7 +297,7 @@ document.addEventListener('DOMContentLoaded', event => { } const disabledBoth = disabledChangedPasswordNotification && disabledAddLoginNotification; if (!disabledBoth && formData[i].usernameEl != null && formData[i].passwordEl != null) { - const login = { + const login: AddLoginRuntimeMessage = { username: formData[i].usernameEl.value, password: formData[i].passwordEl.value, url: document.URL, @@ -343,13 +346,15 @@ document.addEventListener('DOMContentLoaded', event => { if (newPass != null && curPass != null || (newPassOnly && newPass != null)) { processedForm(form); + + const changePasswordRuntimeMessage: ChangePasswordRuntimeMessage = { + newPassword: newPass, + currentPassword: curPass, + url: document.URL, + }; sendPlatformMessage({ command: 'bgChangedPassword', - data: { - newPassword: newPass, - currentPassword: curPass, - url: document.URL, - }, + data: changePasswordRuntimeMessage, }); break; }