Add support for locking single or all databases

This commit is contained in:
varjolintu 2023-08-29 10:26:34 +03:00
parent d3184cc42c
commit 1f86cc3d5a
14 changed files with 176 additions and 44 deletions

View file

@ -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."
}
}

View file

@ -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;
}

View file

@ -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

View file

@ -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();
});

View file

@ -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();
};

View file

@ -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}`);

View file

@ -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;

View file

@ -24,8 +24,14 @@
<button id="options-button" class="btn btn-sm btn-success" data-i18n="[title]popupSettingsText"><i class="fa fa-cog" aria-hidden="true"></i></button>
<button id="choose-custom-login-fields-button" class="btn btn-sm btn-warning" data-i18n="[title]popupChooseCredentialsText"></button>
</div>
<div class="lock-button-area">
<div class="btn-group lock-button-area">
<button id="lock-database-button" class="btn btn-sm btn-danger" data-i18n="[title]lockDatabase"><i class="fa fa-lock" aria-hidden="true"></i></button>
<select id="dropdown-button" class="btn btn-sm btn-danger dropdown-toggle" style="display: none"></select>
</div>
<div class="kpxc-dropdown-menu" style="display: none">
<div class="kpxc-dropdown-item">
<span id="kpxc-dropdown-item" data-i18n="lockAllDatabases"></span>
</div>
</div>
</div>

View file

@ -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 () => {

View file

@ -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();
});
})();

View file

@ -24,8 +24,14 @@
<button id="options-button" class="btn btn-sm btn-success" data-i18n="[title]popupSettingsText"><i class="fa fa-cog" aria-hidden="true"></i></button>
<button id="choose-custom-login-fields-button" class="btn btn-sm btn-warning" data-i18n="[title]popupChooseCredentialsText"></button>
</div>
<div class="lock-button-area">
<div class="btn-group lock-button-area">
<button id="lock-database-button" class="btn btn-sm btn-danger" data-i18n="[title]lockDatabase"><i class="fa fa-lock" aria-hidden="true"></i></button>
<select id="dropdown-button" class="btn btn-sm btn-danger dropdown-toggle" style="display: none"></select>
</div>
<div class="kpxc-dropdown-menu" style="display: none">
<div class="kpxc-dropdown-item">
<span id="dropdown-item" data-i18n="lockAllDatabases"></span>
</div>
</div>
</div>

View file

@ -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 () => {

View file

@ -24,8 +24,14 @@
<button id="options-button" class="btn btn-sm btn-success" data-i18n="[title]popupSettingsText"><i class="fa fa-cog" aria-hidden="true"></i></button>
<button id="choose-custom-login-fields-button" class="btn btn-sm btn-warning" data-i18n="[title]popupChooseCredentialsText"></button>
</div>
<div class="lock-button-area">
<div class="btn-group lock-button-area">
<button id="lock-database-button" class="btn btn-sm btn-danger" data-i18n="[title]lockDatabase"><i class="fa fa-lock" aria-hidden="true"></i></button>
<select id="dropdown-button" class="btn btn-sm btn-danger dropdown-toggle" style="display: none"></select>
</div>
<div class="kpxc-dropdown-menu" style="display: none">
<div class="kpxc-dropdown-item">
<span id="dropdown-item" data-i18n="lockAllDatabases"></span>
</div>
</div>
</div>

View file

@ -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) => {