diff --git a/keepassxc-browser/_locales/en/messages.json b/keepassxc-browser/_locales/en/messages.json index 9b5f6bf..40ad3dc 100644 --- a/keepassxc-browser/_locales/en/messages.json +++ b/keepassxc-browser/_locales/en/messages.json @@ -1202,5 +1202,13 @@ "lockDatabase": { "message": "Lock database", "description": "Lock database button title text." + }, + "lockAllDatabases": { + "message": "Lock all databases", + "description": "Lock all databases button title text." + }, + "noAction": { + "message": "No action", + "description": "No action text." } } diff --git a/keepassxc-browser/background/browserAction.js b/keepassxc-browser/background/browserAction.js index a3b37ee..7e452d9 100755 --- a/keepassxc-browser/background/browserAction.js +++ b/keepassxc-browser/background/browserAction.js @@ -38,7 +38,7 @@ browserAction.showDefault = async function(tab) { // Get the current tab if no tab given tab ??= await getCurrentTab(); - if (!tab) { + if (!tab || tab.id < 0) { return; } diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index 9a654d6..2c0a831 100755 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -166,10 +166,10 @@ kpxcEvent.loadSettings = async function() { }); }; -kpxcEvent.lockDatabase = async function(tab) { +kpxcEvent.lockDatabase = async function(tab, args) { try { - await keepass.lockDatabase(tab); - return kpxcEvent.showStatus(tab, false); + await keepass.lockDatabase(tab, args); + return kpxcEvent.getStatus(tab); } catch (err) { logError('kpxcEvent.lockDatabase error: ' + err); return false; @@ -258,6 +258,7 @@ kpxcEvent.showStatus = async function(tab, configured, internalPoll) { error: errorMessage || null, identifier: keyId, keePassXCAvailable: keepass.isKeePassXCAvailable, + protocolV2: keepass.protocolV2, showGettingStartedGuideAlert: page.settings.showGettingStartedGuideAlert, showTroubleshootingGuideAlert: page.settings.showTroubleshootingGuideAlert, usernameFieldDetected: usernameFieldDetected diff --git a/keepassxc-browser/background/httpauth.js b/keepassxc-browser/background/httpauth.js index 4d15bd7..924c499 100755 --- a/keepassxc-browser/background/httpauth.js +++ b/keepassxc-browser/background/httpauth.js @@ -48,7 +48,7 @@ httpAuth.handleRequestCallback = function(details, callback) { }; httpAuth.retrieveCredentials = async function(tabId, url, submitUrl) { - return await keepass.retrieveCredentials(tabId, [ url, submitUrl, false, true ]).catch((err) => { + return await keepass.getCredentials(tabId, [ url, submitUrl, false, true ]).catch((err) => { logError('httpAuth.retrieveCredentials error: ' + err); return Promise.reject(); }); diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index 4d26900..16fbf59 100755 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -386,14 +386,14 @@ keepass.checkForNewKeePassXCVersion = function() { keepass.latestKeePassXC.lastChecked = new Date().valueOf(); }; -keepass.updatePopup = function() { +keepass.updatePopup = function(tab) { if (page && page.tabs.length > 0) { - browserAction.showDefault(); + browserAction.showDefault(tab); } }; // Updates the database hashes to content script -keepass.updateDatabase = async function() { +keepass.updateDatabase = async function(tab) { if (!keepass.isKeePassXCAvailable) { return; } @@ -406,14 +406,14 @@ keepass.updateDatabase = async function() { // TODO: Only show "Connect" if the active database is not connected? // TODO: What if there are credentials from another database but the selected one is not connected? const result = await protocol.testAssociationFromDatabaseStatuses(); - keepass.updatePopup(); + keepass.updatePopup(tab); keepass.updateDatabaseHashToContent(result); return; } // Legacy protocol await keepassProtocol.testAssociation(null, [ true ]); - keepass.updatePopup(); + keepass.updatePopup(tab); keepass.updateDatabaseHashToContent(); }; diff --git a/keepassxc-browser/background/protocol.js b/keepassxc-browser/background/protocol.js index 458dd0b..fb3f9a7 100644 --- a/keepassxc-browser/background/protocol.js +++ b/keepassxc-browser/background/protocol.js @@ -322,23 +322,21 @@ protocol.lockDatabase = async function(tab, args = []) { return false; } + const [ lockSingle ] = args; + const messageData = { - action: kpActions.LOCK_DATABASE + action: kpActions.LOCK_DATABASE, + lockSingle: lockSingle }; try { const response = await protocolClient.sendMessage(tab, messageData); if (response) { - //keepass.isDatabaseClosed = true; // ? - keepass.updateDatabase(); - - // Display error message in the popup - keepass.handleError(tab, kpErrors.DATABASE_NOT_OPENED); + keepass.updateDatabase(tab); return true; - } else { - //keepass.isDatabaseClosed = true; // ? } + keepass.isDatabaseClosed = true; return false; } catch (err) { logError(`lockDatabase failed: ${err}`); diff --git a/keepassxc-browser/popups/popup.css b/keepassxc-browser/popups/popup.css index f89aa82..db4b60c 100644 --- a/keepassxc-browser/popups/popup.css +++ b/keepassxc-browser/popups/popup.css @@ -97,6 +97,37 @@ code { justify-content: flex-end; } +.dropdown-toggle { + display: none; + height: 31px; + width: 10px; +} + +.kpxc-dropdown-menu { + border: var(--kpxc-card-border-color); + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; + box-shadow: 0 4px 6px 0 hsla(0, 0%, 0%, 0.2) !important; + overflow: hidden;; + position: absolute; + right: 12px; + top: 40px; + z-index: 2147483646; +} + +.kpxc-dropdown-item { + background: var(--kpxc-background-color); + color: var(--kpxc-text-color); + cursor: pointer; + padding: 5px; +} + +.kpxc-dropdown-item:hover { + background-color: #28a745 !important; + color: #ffffff !important; +} + #list { padding-left: 0px; } @@ -185,6 +216,15 @@ code { background-color: var(--kpxc-table-hover-color) !important; } + .kpxc-dropdown-menu { + border: var(--kpxc-card-border-color); + } + + .kpxc-dropdown-item { + background: var(--kpxc-background-color); + color: var(--kpxc-text-color); + } + span.bg-success { background-color: var(--kpxc-table-hover-color) !important; color: var(--kpxc-text-color) !important; diff --git a/keepassxc-browser/popups/popup.html b/keepassxc-browser/popups/popup.html index b4e5365..99ffb4b 100644 --- a/keepassxc-browser/popups/popup.html +++ b/keepassxc-browser/popups/popup.html @@ -24,8 +24,14 @@ -
+
+ +
+
diff --git a/keepassxc-browser/popups/popup.js b/keepassxc-browser/popups/popup.js index 5b556e6..d087193 100644 --- a/keepassxc-browser/popups/popup.js +++ b/keepassxc-browser/popups/popup.js @@ -19,6 +19,7 @@ function statusResponse(status) { $('#configured-not-associated').hide(); $('#lock-database-button').hide(); $('#getting-started-guide').hide(); + hideDropdownButton(); if (!status.keePassXCAvailable) { $('#error-message').textContent = status.error; @@ -38,7 +39,9 @@ function statusResponse(status) { } // Only supported with Protocol V2 - if (status.databaseAssociationStatuses && Object.keys(status.databaseAssociationStatuses).length > 0) { + if (status.protocolV2 + && status.databaseAssociationStatuses + && Object.keys(status.databaseAssociationStatuses).length > 0) { // This can be also shown when isAnyAssociated is true? if (status.databaseAssociationStatuses.associationNeeded) { $('#not-configured').show(); @@ -53,6 +56,7 @@ function statusResponse(status) { $('#configured-and-associated').show(); $('#associated-identifier').textContent = status.identifier; $('#lock-database-button').show(); + showDropdownButton(status.protocolV2); if (status.usernameFieldDetected) { $('#username-field-detected').show(); @@ -156,9 +160,11 @@ const sendMessageToTab = async function(message) { }); $('#lock-database-button').addEventListener('click', async () => { - statusResponse(await browser.runtime.sendMessage({ - action: 'lock_database' - })); + statusResponse(await lockDatabase()); + }); + + $('.kpxc-dropdown-item').addEventListener('click', async () => { + statusResponse(await lockDatabase(false)); }); $('#username-only-button').addEventListener('click', async () => { diff --git a/keepassxc-browser/popups/popup_functions.js b/keepassxc-browser/popups/popup_functions.js index c21a9bd..adf2a95 100644 --- a/keepassxc-browser/popups/popup_functions.js +++ b/keepassxc-browser/popups/popup_functions.js @@ -60,6 +60,39 @@ async function getLoginData() { return logins; } +async function lockDatabase(lockSingle = true) { + return await browser.runtime.sendMessage({ + action: 'lock_database', + args: [ lockSingle ] + }); +} + +// Show the dropdown button if protocol is supported +async function showDropdownButton(isV2) { + const isProtocolV2 = isV2 || await browser.runtime.sendMessage({ action: 'is_protocol_v2' }); + if (isProtocolV2) { + $('.lock-button-area')?.classList.add('btn-group'); + $('#dropdown-button')?.show(); + } else { + $('.lock-button-area')?.classList.remove('btn-group'); + $('#dropdown-button')?.hide(); + } +} + +function hideDropdownButton() { + $('.lock-button-area')?.classList.remove('btn-group'); + $('#dropdown-button')?.hide(); +} + +function hideElementsOnDatabaseLock() { + $('.credentials').hide(); + $('#database-not-opened').show(); + $('#lock-database-button').hide(); + $('#dropdown-button').hide(); + $('#btn-dismiss')?.hide(); + $('#database-error-message').textContent = tr('errorMessageDatabaseNotOpened'); +} + // Sets default popup size for Chromium based browsers to prevent flash on popup open function setDefaultPopupSize() { if (!isFirefox()) { @@ -83,7 +116,36 @@ function resizePopup() { document.addEventListener('DOMContentLoaded', initSettings); } + document.addEventListener('mouseup', function(e) { + if (!e.isTrusted) { + return; + } + + if (e.target.id !== 'kpxc-dropdown-item') { + $('.kpxc-dropdown-menu')?.hide(); + } + }); + updateAvailableResponse(await browser.runtime.sendMessage({ action: 'update_available_keepassxc' })); + + $('#dropdown-button').addEventListener('click', (e) => { + const dropdownMenu = $('.kpxc-dropdown-menu'); + if (!dropdownMenu) { + return; + } + + if (dropdownMenu.style.display === 'none') { + dropdownMenu.show(); + } else { + dropdownMenu.hide(); + } + + e.target.blur(); + }); + + $('.kpxc-dropdown-item').addEventListener('click', () => { + $('.kpxc-dropdown-menu')?.hide(); + }); })(); diff --git a/keepassxc-browser/popups/popup_httpauth.html b/keepassxc-browser/popups/popup_httpauth.html index 9fb2058..fac5919 100644 --- a/keepassxc-browser/popups/popup_httpauth.html +++ b/keepassxc-browser/popups/popup_httpauth.html @@ -24,8 +24,14 @@ -
+
+ +
+
diff --git a/keepassxc-browser/popups/popup_httpauth.js b/keepassxc-browser/popups/popup_httpauth.js index 0a37bfd..1ece64b 100644 --- a/keepassxc-browser/popups/popup_httpauth.js +++ b/keepassxc-browser/popups/popup_httpauth.js @@ -5,6 +5,7 @@ await initColorTheme(); $('#lock-database-button').show(); + await showDropdownButton(); const data = await getLoginData(); const ll = document.getElementById('login-list'); @@ -31,16 +32,14 @@ ll.appendChild(a); } - $('#lock-database-button').addEventListener('click', function() { - browser.runtime.sendMessage({ - action: 'lock_database' - }); + $('#lock-database-button').addEventListener('click', () => { + lockDatabase(); + hideElementsOnDatabaseLock(); + }); - $('.credentials').hide(); - $('#btn-dismiss').hide(); - $('#database-not-opened').show(); - $('#lock-database-button').hide(); - $('#database-error-message').textContent = tr('errorMessageDatabaseNotOpened'); + $('.kpxc-dropdown-item').addEventListener('click', () => { + lockDatabase(false); + hideElementsOnDatabaseLock(); }); $('#btn-dismiss').addEventListener('click', async () => { diff --git a/keepassxc-browser/popups/popup_login.html b/keepassxc-browser/popups/popup_login.html index 42eb4d4..5392e62 100644 --- a/keepassxc-browser/popups/popup_login.html +++ b/keepassxc-browser/popups/popup_login.html @@ -24,8 +24,14 @@ -
+
+ +
+
diff --git a/keepassxc-browser/popups/popup_login.js b/keepassxc-browser/popups/popup_login.js index b063307..ec6d58f 100644 --- a/keepassxc-browser/popups/popup_login.js +++ b/keepassxc-browser/popups/popup_login.js @@ -4,13 +4,14 @@ resizePopup(); await initColorTheme(); - $('#lock-database-button').show(); - const tab = await getCurrentTab(); if (!tab) { return []; } + $('#lock-database-button').show(); + showDropdownButton(); + const logins = await getLoginData(); const ll = document.getElementById('login-list'); @@ -61,15 +62,14 @@ filter.focus(); } - $('#lock-database-button').addEventListener('click', (e) => { - browser.runtime.sendMessage({ - action: 'lock_database' - }); + $('#lock-database-button').addEventListener('click', () => { + lockDatabase(); + hideElementsOnDatabaseLock(); + }); - $('#credentialsList').hide(); - $('#database-not-opened').show(); - $('#lock-database-button').hide(); - $('#database-error-message').textContent = tr('errorMessageDatabaseNotOpened'); + $('.kpxc-dropdown-item').addEventListener('click', () => { + lockDatabase(false); + hideElementsOnDatabaseLock(); }); $('#reopen-database-button').addEventListener('click', (e) => {