diff --git a/CHANGELOG b/CHANGELOG index d517fe6..dd4a225 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ 0.3.5 (??-??-2017) ========================= - Removed database locked/unlocked status polling and replaced it with message handling from KeePassXC signals +- Clear or change page credentials if a database is changed or locked 0.3.4 (14-10-2017) ========================= diff --git a/keepassxc-browser/background/event.js b/keepassxc-browser/background/event.js index ef75bd4..a0de69b 100644 --- a/keepassxc-browser/background/event.js +++ b/keepassxc-browser/background/event.js @@ -1,14 +1,14 @@ -var event = {}; +var kpxcEvent = {}; -event.onMessage = function(request, sender, callback) { - if (request.action in event.messageHandlers) { +kpxcEvent.onMessage = function(request, sender, callback) { + if (request.action in kpxcEvent.messageHandlers) { //console.log('onMessage(' + request.action + ') for #' + sender.tab.id); if (!sender.hasOwnProperty('tab') || sender.tab.id < 1) { sender.tab = {}; sender.tab.id = page.currentTabId; } - event.invoke(event.messageHandlers[request.action], callback, sender.tab.id, request.args); + kpxcEvent.invoke(kpxcEvent.messageHandlers[request.action], callback, sender.tab.id, request.args); // onMessage closes channel for callback automatically // if this method does not return true @@ -29,7 +29,7 @@ event.onMessage = function(request, sender, callback) { * @param {bool} secondTime * @returns null (asynchronous) */ -event.invoke = function(handler, callback, senderTabId, args, secondTime) { +kpxcEvent.invoke = function(handler, callback, senderTabId, args, secondTime) { if (senderTabId < 1) { return; } @@ -51,7 +51,7 @@ event.invoke = function(handler, callback, senderTabId, args, secondTime) { // using window.open() if (!secondTime) { window.setTimeout(function() { - event.invoke(handler, callback, senderTabId, args, true); + kpxcEvent.invoke(handler, callback, senderTabId, args, true); }, 250); } return; @@ -75,12 +75,12 @@ event.invoke = function(handler, callback, senderTabId, args, secondTime) { }); }; -event.onShowAlert = function(callback, tab, message) { +kpxcEvent.onShowAlert = function(callback, tab, message) { if (page.settings.supressAlerts) { console.log(message); } else { alert(message); } }; -event.showStatus = function(configured, tab, callback) { +kpxcEvent.showStatus = function(configured, tab, callback) { let keyId = null; if (configured) { keyId = keepass.keyRing[keepass.databaseHash].id; @@ -99,11 +99,11 @@ event.showStatus = function(configured, tab, callback) { }); }; -event.onLoadSettings = function(callback, tab) { +kpxcEvent.onLoadSettings = function(callback, tab) { page.settings = (typeof(localStorage.settings) === 'undefined') ? {} : JSON.parse(localStorage.settings); }; -event.onLoadKeyRing = function(callback, tab) { +kpxcEvent.onLoadKeyRing = function(callback, tab) { keepass.keyRing = (typeof(localStorage.keyRing) === 'undefined') ? {} : JSON.parse(localStorage.keyRing); if (keepass.isAssociated() && !keepass.keyRing[keepass.associated.hash]) { keepass.associated = { @@ -113,25 +113,25 @@ event.onLoadKeyRing = function(callback, tab) { } }; -event.onGetSettings = function(callback, tab) { - event.onLoadSettings(); +kpxcEvent.onGetSettings = function(callback, tab) { + kpxcEvent.onLoadSettings(); callback({ data: page.settings }); }; -event.onSaveSettings = function(callback, tab, settings) { +kpxcEvent.onSaveSettings = function(callback, tab, settings) { localStorage.settings = JSON.stringify(settings); - event.onLoadSettings(); + kpxcEvent.onLoadSettings(); }; -event.onGetStatus = function(callback, tab) { +kpxcEvent.onGetStatus = function(callback, tab) { keepass.testAssociation((response) => { keepass.isConfigured((configured) => { - event.showStatus(configured, tab, callback); + kpxcEvent.showStatus(configured, tab, callback); }); }, tab, true); }; -event.onReconnect = function(callback, tab) { +kpxcEvent.onReconnect = function(callback, tab) { keepass.connectToNative(); // Add a small timeout after reconnecting. Just to make sure. It's not pretty, I know :( @@ -142,7 +142,7 @@ event.onReconnect = function(callback, tab) { if (gdRes) { keepass.testAssociation((response) => { keepass.isConfigured((configured) => { - event.showStatus(configured, tab, callback); + kpxcEvent.showStatus(configured, tab, callback); }); }, tab); } @@ -151,30 +151,30 @@ event.onReconnect = function(callback, tab) { }, 2000); }; -event.lockDatabase = function(callback, tab) { +kpxcEvent.lockDatabase = function(callback, tab) { keepass.lockDatabase((response) => { - event.showStatus(true, tab, callback); + kpxcEvent.showStatus(true, tab, callback); }, tab); }; -event.onPopStack = function(callback, tab) { +kpxcEvent.onPopStack = function(callback, tab) { browserAction.stackPop(tab.id); browserAction.show(null, tab); }; -event.onGetTabInformation = function(callback, tab) { +kpxcEvent.onGetTabInformation = function(callback, tab) { const id = tab.id || page.currentTabId; callback(page.tabs[id]); }; -event.onGetConnectedDatabase = function(callback, tab) { +kpxcEvent.onGetConnectedDatabase = function(callback, tab) { callback({ count: Object.keys(keepass.keyRing).length, identifier: (keepass.keyRing[keepass.associated.hash]) ? keepass.keyRing[keepass.associated.hash].id : null }); }; -event.onGetKeePassXCVersions = function(callback, tab) { +kpxcEvent.onGetKeePassXCVersions = function(callback, tab) { if (keepass.currentKeePassXC.version === 0) { keepass.getDatabaseHash((response) => { callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version}); @@ -183,25 +183,25 @@ event.onGetKeePassXCVersions = function(callback, tab) { callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version}); }; -event.onCheckUpdateKeePassXC = function(callback, tab) { +kpxcEvent.onCheckUpdateKeePassXC = function(callback, tab) { keepass.checkForNewKeePassXCVersion(); callback({current: keepass.currentKeePassXC.version, latest: keepass.latestKeePassXC.version}); }; -event.onUpdateAvailableKeePassXC = function(callback, tab) { +kpxcEvent.onUpdateAvailableKeePassXC = function(callback, tab) { callback(keepass.keePassXCUpdateAvailable()); }; -event.onRemoveCredentialsFromTabInformation = function(callback, tab) { +kpxcEvent.onRemoveCredentialsFromTabInformation = function(callback, tab) { const id = tab.id || page.currentTabId; page.clearCredentials(id); }; -event.onSetRememberPopup = function(callback, tab, username, password, url, usernameExists, credentialsList) { +kpxcEvent.onSetRememberPopup = function(callback, tab, username, password, url, usernameExists, credentialsList) { browserAction.setRememberPopup(tab.id, username, password, url, usernameExists, credentialsList); }; -event.onLoginPopup = function(callback, tab, logins) { +kpxcEvent.onLoginPopup = function(callback, tab, logins) { let stackData = { level: 1, iconType: 'questionmark', @@ -212,7 +212,7 @@ event.onLoginPopup = function(callback, tab, logins) { browserAction.show(null, tab); }; -event.onHTTPAuthPopup = function(callback, tab, data) { +kpxcEvent.onHTTPAuthPopup = function(callback, tab, data) { let stackData = { level: 1, iconType: 'questionmark', @@ -223,7 +223,7 @@ event.onHTTPAuthPopup = function(callback, tab, data) { browserAction.show(null, tab); }; -event.onMultipleFieldsPopup = function(callback, tab) { +kpxcEvent.onMultipleFieldsPopup = function(callback, tab) { let stackData = { level: 1, iconType: 'normal', @@ -233,38 +233,46 @@ event.onMultipleFieldsPopup = function(callback, tab) { browserAction.show(null, tab); }; -event.pageClearLogins = function(callback, tab) { +kpxcEvent.pageClearLogins = function(callback, tab) { page.clearLogins(tab.id); callback(); }; +kpxcEvent.oldDatabaseHash = 'no-hash'; +kpxcEvent.checkDatabaseHash = function(callback, tab) { + keepass.getDatabaseHash((response) => { + callback({old: kpxcEvent.oldDatabaseHash, new: response}); + kpxcEvent.oldDatabaseHash = response; + }); +}; // all methods named in this object have to be declared BEFORE this! -event.messageHandlers = { +kpxcEvent.messageHandlers = { 'add_credentials': keepass.addCredentials, - 'alert': event.onShowAlert, + 'alert': kpxcEvent.onShowAlert, 'associate': keepass.associate, - 'check_update_keepassxc': event.onCheckUpdateKeePassXC, - 'get_connected_database': event.onGetConnectedDatabase, - 'get_keepassxc_versions': event.onGetKeePassXCVersions, - 'get_settings': event.onGetSettings, - 'get_status': event.onGetStatus, - 'get_tab_information': event.onGetTabInformation, - 'load_keyring': event.onLoadKeyRing, - 'load_settings': event.onLoadSettings, - 'page_clear_logins': event.pageClearLogins, - 'pop_stack': event.onPopStack, - 'popup_login': event.onLoginPopup, - 'popup_multiple-fields': event.onMultipleFieldsPopup, - 'remove_credentials_from_tab_information': event.onRemoveCredentialsFromTabInformation, + 'check_update_keepassxc': kpxcEvent.onCheckUpdateKeePassXC, + 'get_connected_database': kpxcEvent.onGetConnectedDatabase, + 'get_keepassxc_versions': kpxcEvent.onGetKeePassXCVersions, + 'get_settings': kpxcEvent.onGetSettings, + 'get_status': kpxcEvent.onGetStatus, + 'get_tab_information': kpxcEvent.onGetTabInformation, + 'load_keyring': kpxcEvent.onLoadKeyRing, + 'load_settings': kpxcEvent.onLoadSettings, + 'page_clear_logins': kpxcEvent.pageClearLogins, + 'pop_stack': kpxcEvent.onPopStack, + 'popup_login': kpxcEvent.onLoginPopup, + 'popup_multiple-fields': kpxcEvent.onMultipleFieldsPopup, + 'remove_credentials_from_tab_information': kpxcEvent.onRemoveCredentialsFromTabInformation, 'retrieve_credentials': keepass.retrieveCredentials, 'show_default_browseraction': browserAction.showDefault, 'update_credentials': keepass.updateCredentials, - 'save_settings': event.onSaveSettings, - 'set_remember_credentials': event.onSetRememberPopup, + 'save_settings': kpxcEvent.onSaveSettings, + 'set_remember_credentials': kpxcEvent.onSetRememberPopup, 'stack_add': browserAction.stackAdd, - 'update_available_keepassxc': event.onUpdateAvailableKeePassXC, + 'update_available_keepassxc': kpxcEvent.onUpdateAvailableKeePassXC, 'generate_password': keepass.generatePassword, - 'reconnect': event.onReconnect, - 'lock-database': event.lockDatabase + 'reconnect': kpxcEvent.onReconnect, + 'lock-database': kpxcEvent.lockDatabase, + 'check_databasehash': kpxcEvent.checkDatabaseHash }; diff --git a/keepassxc-browser/background/httpauth.js b/keepassxc-browser/background/httpauth.js index 06936d6..f1ad0ba 100644 --- a/keepassxc-browser/background/httpauth.js +++ b/keepassxc-browser/background/httpauth.js @@ -41,7 +41,7 @@ httpAuth.processPendingCallbacks = function(details, resolve, reject) { httpAuth.loginOrShowCredentials = function(logins, details, resolve, reject) { // at least one login found --> use first to login if (logins.length > 0) { - event.onHTTPAuthPopup(null, { "id": details.tabId }, { "logins": logins, "url": details.searchUrl }); + kpxcEvent.onHTTPAuthPopup(null, { "id": details.tabId }, { "logins": logins, "url": details.searchUrl }); //generate popup-list for HTTP Auth usernames + descriptions if (page.settings.autoFillAndSend) { diff --git a/keepassxc-browser/background/init.js b/keepassxc-browser/background/init.js index 72b4b9d..6bc33c1 100644 --- a/keepassxc-browser/background/init.js +++ b/keepassxc-browser/background/init.js @@ -22,7 +22,7 @@ browser.tabs.onCreated.addListener((tab) => { //console.log('browser.tabs.onCreated(' + tab.id+ ')'); if (tab.selected) { page.currentTabId = tab.id; - event.invoke(page.switchTab, null, tab.id, []); + kpxcEvent.invoke(page.switchTab, null, tab.id, []); } } }); @@ -53,8 +53,8 @@ browser.tabs.onActivated.addListener((activeInfo) => { if (info && info.id) { page.currentTabId = info.id; if (info.status === 'complete') { - //console.log('event.invoke(page.switchTab, null, '+info.id + ', []);'); - event.invoke(page.switchTab, null, info.id, []); + //console.log('kpxcEvent.invoke(page.switchTab, null, '+info.id + ', []);'); + kpxcEvent.invoke(page.switchTab, null, info.id, []); } } }); @@ -67,7 +67,7 @@ browser.tabs.onActivated.addListener((activeInfo) => { */ browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { if (changeInfo.status === 'complete') { - event.invoke(browserAction.removeRememberPopup, null, tabId, []); + kpxcEvent.invoke(browserAction.removeRememberPopup, null, tabId, []); } }); @@ -87,7 +87,7 @@ if (browser.webRequest.onAuthRequired) { browser.webRequest.onErrorOccurred.addListener(httpAuth.requestCompleted, opts); } -browser.runtime.onMessage.addListener(event.onMessage); +browser.runtime.onMessage.addListener(kpxcEvent.onMessage); const contextMenuItems = [ {title: 'Fill &User + Pass', action: 'fill_user_pass'}, @@ -131,4 +131,4 @@ browser.commands.onCommand.addListener((command) => { // Interval which updates the browserAction (e.g. blinking icon) window.setInterval(function() { browserAction.update(_interval); -}, _interval); \ No newline at end of file +}, _interval); diff --git a/keepassxc-browser/background/keepass.js b/keepassxc-browser/background/keepass.js index 1605099..69fb55b 100644 --- a/keepassxc-browser/background/keepass.js +++ b/keepassxc-browser/background/keepass.js @@ -1,3 +1,5 @@ +'use strict'; + var keepass = {}; keepass.associated = {'value': false, 'hash': null}; @@ -20,7 +22,7 @@ keepass.databaseHash = 'no-hash'; //no-hash = KeePassXC is too old and does not keepass.keyRing = (typeof(localStorage.keyRing) === 'undefined') ? {} : JSON.parse(localStorage.keyRing); keepass.keyId = 'keepassxc-browser-cryptokey-name'; keepass.keyBody = 'keepassxc-browser-key'; -keepass.messageTimeout = 1000; // milliseconds +keepass.messageTimeout = 500; // milliseconds const kpActions = { SET_LOGIN: 'set-login', diff --git a/keepassxc-browser/background/page.js b/keepassxc-browser/background/page.js index 0a6baba..8ffd51e 100644 --- a/keepassxc-browser/background/page.js +++ b/keepassxc-browser/background/page.js @@ -16,7 +16,7 @@ page.settings = (typeof(localStorage.settings) === 'undefined') ? {} : JSON.pars page.blockedTabs = {}; page.initSettings = function() { - event.onLoadSettings(); + kpxcEvent.onLoadSettings(); if (!('checkUpdateKeePassXC' in page.settings)) { page.settings.checkUpdateKeePassXC = defaultSettings.checkUpdateKeePassXC; } diff --git a/keepassxc-browser/keepassxc-browser.js b/keepassxc-browser/keepassxc-browser.js index 7de7bea..e3857f9 100644 --- a/keepassxc-browser/keepassxc-browser.js +++ b/keepassxc-browser/keepassxc-browser.js @@ -202,7 +202,7 @@ cipPassword.createDialog = function() { const $dialog = jQuery('
') .addClass('dialog-form') .attr('id', 'cip-genpw-dialog'); - + const $inputDiv = jQuery('
').addClass('form-group'); const $inputGroup = jQuery('
').addClass('genpw-input-group'); const $textfieldPassword = jQuery('') @@ -220,7 +220,7 @@ cipPassword.createDialog = function() { .attr('id', 'cip-genpw-quality') .text('123 Bits'); $inputGroup.append($textfieldPassword).append($quality); - + const $checkGroup = jQuery('
').addClass('genpw-input-group'); const $checkboxNextField = jQuery('') .attr('id', 'cip-genpw-checkbox-next-field') @@ -246,7 +246,7 @@ cipPassword.createDialog = function() { title: 'Password Generator', classes: {'ui-dialog': 'ui-corner-all'}, buttons: { - 'Generate': + 'Generate': { text: 'Generate', id: 'cip-genpw-btn-generate', @@ -266,7 +266,7 @@ cipPassword.createDialog = function() { cipPassword.copyPasswordToClipboard(); } }, - 'Fill & copy': + 'Fill & copy': { text: 'Fill & copy', id: 'cip-genpw-btn-fillin', @@ -1102,6 +1102,7 @@ cip.credentials = []; jQuery(function() { cip.init(); cip.detectNewActiveFields(); + cip.detectDatabaseChange(); }); cip.init = function() { @@ -1128,6 +1129,37 @@ cip.detectNewActiveFields = function() { //} }; +// Switch credentials if database is changed or closed +cip.detectDatabaseChange = function() { + const dbDetectInterval = setInterval(function() { + browser.runtime.sendMessage({ + action: 'check_databasehash' + }).then((response) => { + if (response.new === 'no-hash') { + cipEvents.clearCredentials(); + + browser.runtime.sendMessage({ + action: 'page_clear_logins' + }); + + // Switch back to default popup + browser.runtime.sendMessage({ + action: 'get_status' + }); + } else { + if (response.new !== 'no-hash' && response.new !== response.old) { + browser.runtime.sendMessage({ + action: 'get_settings', + }).then((response) => { + cip.settings = response.data; + cip.initCredentialFields(true); + }); + } + } + }); + }, 1000); +}; + cip.initCredentialFields = function(forceCall) { if (_called.initCredentialFields && !forceCall) { return;