From 9e9314722bf6da9450f410516165005d00416734 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Sun, 22 Sep 2024 15:07:35 +0300 Subject: [PATCH 1/2] Update popup content dynamically --- .eslintrc | 7 +- keepassxc-browser/background/browserAction.js | 39 +++--- keepassxc-browser/background/client.js | 2 +- keepassxc-browser/background/event.js | 20 +-- keepassxc-browser/background/init.js | 2 +- keepassxc-browser/background/keepass.js | 30 ++-- keepassxc-browser/background/page.js | 10 +- keepassxc-browser/common/global.js | 55 +++++--- keepassxc-browser/content/autocomplete.js | 4 +- keepassxc-browser/popups/popup.html | 40 +++++- keepassxc-browser/popups/popup.js | 132 ++++++++++++------ keepassxc-browser/popups/popup_functions.js | 97 ++++++++++++- keepassxc-browser/popups/popup_httpauth.html | 65 --------- keepassxc-browser/popups/popup_httpauth.js | 54 ------- keepassxc-browser/popups/popup_login.html | 63 --------- keepassxc-browser/popups/popup_login.js | 80 ----------- 16 files changed, 325 insertions(+), 375 deletions(-) delete mode 100644 keepassxc-browser/popups/popup_httpauth.html delete mode 100644 keepassxc-browser/popups/popup_httpauth.js delete mode 100644 keepassxc-browser/popups/popup_login.html delete mode 100644 keepassxc-browser/popups/popup_login.js diff --git a/.eslintrc b/.eslintrc index 5ddc93e61..b43c55c69 100644 --- a/.eslintrc +++ b/.eslintrc @@ -122,6 +122,8 @@ "importScripts": "readonly", "IMPROVED_DETECTION_PREDEFINED_SITELIST": "readonly", "initColorTheme": "readonly", + "initializeHttpAuthLoginList": "readonly", + "initializeLoginList": "readonly", "isEdge": "readonly", "isFirefox": "readonly", "keepass": "readonly", @@ -164,9 +166,12 @@ "ORANGE_BUTTON": "readonly", "page": "readonly", "Pixels": "readonly", - "PublicKeyCredential": "readonly", + "PopupIcon": "readonly", + "PopupState": "readonly", "PREDEFINED_SITELIST": "readonly", + "PublicKeyCredential": "readonly", "RED_BUTTON": "readonly", + "removeAllChildren": "readonly", "retrieveColorScheme": "readonly", "sendMessage": "readonly", "showNotification": "readonly", diff --git a/keepassxc-browser/background/browserAction.js b/keepassxc-browser/background/browserAction.js index 1a28354b7..423dee752 100755 --- a/keepassxc-browser/background/browserAction.js +++ b/keepassxc-browser/background/browserAction.js @@ -3,7 +3,7 @@ const browserActionWrapper = browser.action || browser.browserAction; const browserAction = {}; -browserAction.show = async function(tab, popupData) { +browserAction.updatePopupIcon = async function(tab, popupData) { popupData ??= page.popupData; page.popupData = popupData; @@ -12,15 +12,10 @@ browserAction.show = async function(tab, popupData) { }); if (popupData.popup && tab?.id) { - browserActionWrapper.setPopup({ - tabId: tab.id, - popup: `popups/${popupData.popup}.html` - }); - let badgeText = ''; - if (popupData.popup === 'popup_login') { + if (popupData.popup === PopupState.LOGIN) { badgeText = page.tabs[tab.id]?.loginList?.length; - } else if (popupData.popup === 'popup_httpauth') { + } else if (popupData.popup === PopupState.HTTP_AUTH) { badgeText = page.tabs[tab.id]?.loginList?.logins?.length; } @@ -28,10 +23,10 @@ browserAction.show = async function(tab, popupData) { } }; -browserAction.showDefault = async function(tab) { +browserAction.updatePopup = async function(tab) { const popupData = { - iconType: 'normal', - popup: 'popup' + iconType: PopupIcon.NORMAL, + popup: PopupState.DEFAULT }; const response = await keepass.isConfigured().catch((err) => { @@ -39,11 +34,11 @@ browserAction.showDefault = async function(tab) { }); if (!response && !keepass.isKeePassXCAvailable) { - popupData.iconType = 'cross'; + popupData.iconType = PopupIcon.CROSS; } else if (!keepass.isAssociated() && !keepass.isDatabaseClosed) { - popupData.iconType = 'bang'; + popupData.iconType = PopupIcon.BANG; } else if (keepass.isKeePassXCAvailable && keepass.isDatabaseClosed) { - popupData.iconType = 'locked'; + popupData.iconType = PopupIcon.LOCKED; } // Get the current tab if no tab given @@ -52,13 +47,21 @@ browserAction.showDefault = async function(tab) { return; } + // Credentials are available if (page?.tabs[tab.id]?.loginList.length > 0) { - popupData.iconType = 'normal'; - popupData.popup = 'popup_login'; + popupData.iconType = PopupIcon.NORMAL; + popupData.popup = PopupState.LOGIN; browserAction.setBadgeText(tab?.id, page.tabs[tab.id]?.loginList.length); } - await browserAction.show(tab, popupData); + // HTTP Basic Auth credentials are available + if (page.tabs[tab.id]?.loginList?.logins?.length > 0) { + popupData.iconType = PopupIcon.NORMAL; + popupData.popup = PopupState.HTTP_AUTH; + browserAction.setBadgeText(tab?.id, page.tabs[tab.id]?.loginList?.logins?.length); + } + + await browserAction.updatePopupIcon(tab, popupData); }; browserAction.setBadgeText = function(tabId, badgeText) { @@ -73,7 +76,7 @@ browserAction.setBadgeText = function(tabId, badgeText) { browserAction.generateIconName = async function(iconType) { let name = 'icon_'; name += (await keepass.keePassXCUpdateAvailable()) ? 'new_' : ''; - name += (!iconType || iconType === 'normal') ? 'normal' : iconType; + name += (!iconType || iconType === PopupIcon.NORMAL) ? PopupIcon.NORMAL : iconType; let style = 'colored'; if (page?.settings?.useMonochromeToolbarIcon) { diff --git a/keepassxc-browser/background/client.js b/keepassxc-browser/background/client.js index c98b01dec..b6f0d2d01 100644 --- a/keepassxc-browser/background/client.js +++ b/keepassxc-browser/background/client.js @@ -398,7 +398,7 @@ function onDisconnected() { keepass.databaseHash = ''; page.clearAllLogins(); - keepass.updatePopup('cross'); + keepass.updatePopup(PopupIcon.CROSS); keepass.updateDatabaseHashToContent(); logError(`Failed to connect: ${(browser.runtime.lastError === null ? 'Unknown error' : browser.runtime.lastError.message)}`); } diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index a6d30555a..d285de9b4 100755 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -21,7 +21,7 @@ kpxcEvent.showStatus = async function(tab, configured, internalPoll) { } if (!internalPoll) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); } const errorMessage = page.tabs[tab.id]?.errorMessage ?? undefined; @@ -30,7 +30,6 @@ kpxcEvent.showStatus = async function(tab, configured, internalPoll) { return { associated: keepass.isAssociated(), - configured: configured, databaseClosed: keepass.isDatabaseClosed, encryptionKeyUnrecognized: keepass.isEncryptionKeyUnrecognized, @@ -38,6 +37,7 @@ kpxcEvent.showStatus = async function(tab, configured, internalPoll) { iframeDetected: iframeDetected, identifier: keyId, keePassXCAvailable: keepass.isKeePassXCAvailable, + popupData: page.popupData, showGettingStartedGuideAlert: page.settings.showGettingStartedGuideAlert, showTroubleshootingGuideAlert: page.settings.showTroubleshootingGuideAlert, usernameFieldDetected: usernameFieldDetected @@ -154,13 +154,13 @@ kpxcEvent.onRemoveCredentialsFromTabInformation = async function(tab) { kpxcEvent.onLoginPopup = async function(tab, logins) { const popupData = { - iconType: 'normal', - popup: 'popup_login' + iconType: PopupIcon.NORMAL, + popup: PopupState.LOGIN }; if (tab?.id) { page.tabs[tab.id].loginList = logins; - await browserAction.show(tab, popupData); + await browserAction.updatePopupIcon(tab, popupData); } }; @@ -170,12 +170,14 @@ kpxcEvent.initHttpAuth = async function() { kpxcEvent.onHTTPAuthPopup = async function(tab, data) { const popupData = { - iconType: 'normal', - popup: 'popup_httpauth' + iconType: PopupIcon.NORMAL, + popup: PopupState.HTTP_AUTH }; - page.tabs[tab.id].loginList = data; - await browserAction.show(tab, popupData); + if (tab?.id) { + page.tabs[tab.id].loginList = data; + await browserAction.updatePopupIcon(tab, popupData); + } }; kpxcEvent.onUsernameFieldDetected = async function(tab, detected) { diff --git a/keepassxc-browser/background/init.js b/keepassxc-browser/background/init.js index 73b2550d3..94d382eda 100644 --- a/keepassxc-browser/background/init.js +++ b/keepassxc-browser/background/init.js @@ -82,7 +82,7 @@ const initListeners = async function() { } if (changeInfo.status === 'complete' && tab?.id) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); if (!page.tabs[tab.id]) { page.createTabEntry(tab.id); } diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index ae6ec86ae..c1918d9ae 100755 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -55,7 +55,7 @@ keepass.updateCredentials = async function(tab, args = []) { const [ entryId, username, password, url, group, groupUuid ] = args; const taResponse = await keepass.testAssociation(tab); if (!taResponse) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } @@ -108,7 +108,7 @@ keepass.retrieveCredentials = async function(tab, args = []) { const [ url, submiturl, triggerUnlock = false, httpAuth = false ] = args; const taResponse = await keepass.testAssociation(tab, [ false, triggerUnlock ]); if (!taResponse) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } @@ -145,14 +145,14 @@ keepass.retrieveCredentials = async function(tab, args = []) { if (entries.length === 0) { // Questionmark-icon is not triggered, so we have to trigger for the normal symbol - browserAction.showDefault(tab); + browserAction.updatePopup(tab); } logDebug(`Found ${entries.length} entries for url ${url}`); return entries; } - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } catch (err) { logError(`retrieveCredentials failed: ${err}`); @@ -168,7 +168,7 @@ keepass.generatePassword = async function(tab) { try { const taResponse = await keepass.testAssociation(tab); if (!taResponse) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return ''; } @@ -235,7 +235,7 @@ keepass.associate = async function(tab) { keepass.associated.value = true; keepass.associated.hash = response.hash || 0; - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return AssociatedAction.NEW_ASSOCIATION; } @@ -468,7 +468,7 @@ keepass.getDatabaseGroups = async function(tab) { try { const taResponse = await keepass.testAssociation(tab, [ false ]); if (!taResponse) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } @@ -495,7 +495,7 @@ keepass.getDatabaseGroups = async function(tab) { return groups; } - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } catch (err) { logError(`getDatabaseGroups failed: ${err}`); @@ -508,7 +508,7 @@ keepass.createNewGroup = async function(tab, args = []) { const [ groupName ] = args; const taResponse = await keepass.testAssociation(tab, [ false ]); if (!taResponse) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } @@ -534,7 +534,7 @@ keepass.createNewGroup = async function(tab, args = []) { logError('getDatabaseGroups rejected'); } - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } catch (err) { logError(`createNewGroup failed: ${err}`); @@ -602,7 +602,7 @@ keepass.passkeysRegister = async function(tab, args = []) { try { const taResponse = await keepass.testAssociation(tab, [ false ]); if (!taResponse || !keepass.isConnected || args.length < 2) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } @@ -623,7 +623,7 @@ keepass.passkeysRegister = async function(tab, args = []) { return response; } - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } catch (err) { logError(`passkeysRegister failed: ${err}`); @@ -635,7 +635,7 @@ keepass.passkeysGet = async function(tab, args = []) { try { const taResponse = await keepass.testAssociation(tab, [ false ]); if (!taResponse || !keepass.isConnected || args.length < 2) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } @@ -656,7 +656,7 @@ keepass.passkeysGet = async function(tab, args = []) { return response; } - browserAction.showDefault(tab); + browserAction.updatePopup(tab); return []; } catch (err) { logError(`passkeysGet failed: ${err}`); @@ -910,7 +910,7 @@ keepass.handleError = function(tab, errorCode, errorMessage = '') { keepass.updatePopup = function() { if (page && page.tabs.length > 0) { - browserAction.showDefault(); + browserAction.updatePopup(); } }; diff --git a/keepassxc-browser/background/page.js b/keepassxc-browser/background/page.js index 5a9f8a030..d5d3456a2 100755 --- a/keepassxc-browser/background/page.js +++ b/keepassxc-browser/background/page.js @@ -56,8 +56,8 @@ page.submittedCredentials = {}; page.tabs = []; page.popupData = { - iconType: 'normal', - popup: 'popup' + iconType: PopupIcon.NORMAL, + popup: PopupState.DEFAULT }; page.initSettings = async function() { @@ -118,7 +118,7 @@ page.initOpenedTabs = async function() { } page.currentTabId = currentTab?.id; - browserAction.showDefault(currentTab); + browserAction.updatePopup(currentTab); } catch (err) { logError('page.initOpenedTabs error: ' + err); return Promise.reject(); @@ -154,7 +154,7 @@ page.switchTab = async function(tab) { } }, page.settings.clearCredentialsTimeout * 1000); - browserAction.showDefault(tab); + browserAction.updatePopup(tab); if (tab?.id) { browser.tabs.sendMessage(tab.id, { action: 'activated_tab' }).catch((e) => { logError('Cannot send activated_tab message: ' + e.message); @@ -397,7 +397,7 @@ page.updateContextMenu = async function(tab, credentials) { }; page.updatePopup = function(tab) { - browserAction.showDefault(tab); + browserAction.updatePopup(tab); }; page.setAllowIframes = async function(tab, args = []) { diff --git a/keepassxc-browser/common/global.js b/keepassxc-browser/common/global.js index 55de510e7..03eac4eed 100755 --- a/keepassxc-browser/common/global.js +++ b/keepassxc-browser/common/global.js @@ -26,23 +26,6 @@ const URL_WILDCARD = '1kpxcwc1'; const schemeSegment = '(\\*|http|https|ws|wss|ftp)'; const hostSegment = '(\\*|(?:\\*\\.)?(?:[^/*]+))?'; -const isFirefox = function() { - return navigator.userAgent.indexOf('Firefox') !== -1 || navigator.userAgent.indexOf('Gecko/') !== -1; -}; - -const isEdge = function() { - return navigator.userAgent.indexOf('Edg') !== -1; -}; - -const showNotification = function(message) { - browser.notifications.create({ - 'type': 'basic', - 'iconUrl': browser.runtime.getURL('icons/keepassxc_64x64.png'), - 'title': 'KeePassXC-Browser', - 'message': message - }); -}; - const AssociatedAction = { NOT_ASSOCIATED: 0, ASSOCIATED: 1, @@ -61,6 +44,38 @@ const ManualFill = { BOTH: 2 }; +// Popup icon types +const PopupIcon = { + BANG: 'bang', + CROSS: 'cross', + LOCKED: 'locked', + NORMAL: 'normal' +}; + +// Popup states +const PopupState = { + DEFAULT: 'default', + HTTP_AUTH: 'http_auth', + LOGIN: 'login' +}; + +const isFirefox = function() { + return navigator.userAgent.indexOf('Firefox') !== -1 || navigator.userAgent.indexOf('Gecko/') !== -1; +}; + +const isEdge = function() { + return navigator.userAgent.indexOf('Edg') !== -1; +}; + +const showNotification = function(message) { + browser.notifications.create({ + 'type': 'basic', + 'iconUrl': browser.runtime.getURL('icons/keepassxc_64x64.png'), + 'title': 'KeePassXC-Browser', + 'message': message + }); +}; + const compareVersion = function(minimum, current, canBeEqual = true) { if (!minimum || !current || minimum?.indexOf('.') === -1 || current?.indexOf('.') === -1) { return false; @@ -182,6 +197,12 @@ const getCurrentTab = async function() { return tabs?.length > 0 ? tabs[0] : undefined; }; +const removeAllChildren = function(elem) { + while (elem?.hasChildNodes()) { + elem.removeChild(elem.lastChild); + } +}; + // Exports for tests if (typeof module === 'object') { module.exports = { diff --git a/keepassxc-browser/content/autocomplete.js b/keepassxc-browser/content/autocomplete.js index 4c98d4b00..6c5effa37 100644 --- a/keepassxc-browser/content/autocomplete.js +++ b/keepassxc-browser/content/autocomplete.js @@ -140,9 +140,7 @@ class Autocomplete { await kpxc.updateTOTPList(); // Clear the login items from div - while (this.list.hasChildNodes()) { - this.list.removeChild(this.list.lastChild); - } + removeAllChildren(this.list); // Update credentials to menu div for (const c of this.elements) { diff --git a/keepassxc-browser/popups/popup.html b/keepassxc-browser/popups/popup.html index 7f842d0c4..3d63f974c 100644 --- a/keepassxc-browser/popups/popup.html +++ b/keepassxc-browser/popups/popup.html @@ -18,6 +18,7 @@
+
+ +

@@ -121,6 +133,29 @@

+ + + + + + +

@@ -132,6 +167,7 @@
+